home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / dvi2ps / dvi-to-ps / dvi2ps.c < prev    next >
C/C++ Source or Header  |  1990-10-01  |  75KB  |  2,542 lines

  1. #define VERSION "2.10gf"
  2. /* modified by Peter Damron 1987 University of Washington */
  3. /*---------------------------------------------------------------------*/
  4. /* $Header: dvi2ps.c,v 2.1 88/06/08 14:12:24 peterd Rel2 $ */
  5. /*---------------------------------------------------------------------*/
  6. #ifndef lint
  7. static char rcsid[] = "$Header: dvi2ps.c,v 2.1 88/06/08 14:12:24 peterd Rel2 $";
  8. #endif lint
  9. /*---------------------------------------------------------------------*/
  10. /*
  11.  * AUTHOR(s)
  12.  *     Mark Senn wrote the early versions of this program for the
  13.  *     BBN BitGraph.  Stephan Bechtolsheim, Bob Brown, Richard
  14.  *     Furuta, James Schaad and Robert Wells improved it.  Norm
  15.  *     Hutchinson ported the program to the Sun.  Neal Holtz ported
  16.  *     it to the Apollo, and from there to producing PostScript
  17.  *     output. Scott Jones added intelligent font substitution.
  18.  *     Howard Trickey made it read GF files instead of PXL ones.
  19.  *
  20.  */
  21.  
  22. /*---------------------------------------------------------------------*/
  23. /* Basic method:
  24.  * Using the local font cacheing machinery that was in the previewer,
  25.  * we can easily manage to send the bitmap for each chracter only once.
  26.  * Two passes are made over each page in the DVI file.  The first pass
  27.  * simply outputs the bitmaps for all characters on that page that haven't
  28.  * been sent before.  The second pass outputs all the character setting
  29.  * and positioning commands.  This allows us to bracket the setting portion
  30.  * with PostScript save's and restore's, thus reclaiming considerable
  31.  * virtual memory after each page.
  32.  *
  33.  * All coordinates are output in the PostScript system (TeX origin),
  34.  * and in integer units of rasters (300/inch) -- except for character
  35.  * widths, which are sent as floating point numbers.
  36.  *
  37.  * About 2 pages of PostScript support code must be sent to the LaserWriter
  38.  * before this stuff goes.  It is automatically included unless the
  39.  * -h option is given.
  40.  */
  41.  
  42. /*---------------------------------------------------------------------*/
  43. /* Change log:
  44.  *
  45.  * Early 1985, (nmh) -- ported sun version to Apollo. 
  46.  * A little later (nmh) -- changed to continue on in the event of missing
  47.  *        font files.
  48.  * 30-Mar-85 (nmh) -- added -a option to specify a different PXL area
  49.  * 30-Mar-85 (nmh) -- changed default PXL area to /pxl118
  50.  * 31-Mar-85 (nmh) -- fixed bug in OpenFontFile() regarding more than MAXOPEN
  51.  *              PXL files -- changed to mark files as closed in font_entry.
  52.  *  7-Apr-85 (nmh) -- made command line argument decoding case insensitive.
  53.  *              cleaned up handling of DVI file name argument.
  54.  * 30-May-85 (nmh) -- new version; hacked to output PostScript commands
  55.  *  6-Jun-85 (nmh) -- added relative positioning (20% smaller PostScript output)
  56.  *              add -m option to specify mag
  57.  * 11-Jun-85 (nmh) -- fixed bug regarding char spacings in very long "words"
  58.  * 12-Jun-85 (nmh) -- v1.02 - process DVI pages in reverse order
  59.  * 13-Jun-85 (nmh) -- fixed bug re PXL files getting opened too often when no PreLoad
  60.  * 14-Jun-85 (nmh) -- font dict created in PostScript only when 1st char of font downloaded
  61.  *              add -m0 -mh -m1 etc. to specify magsteps
  62.  * 16-Aug-85 (nmh) -- added -c option t0 create output file in spool area (Apollo specific)
  63.  *              added -h option to copy header file to output
  64.  *              added -o option to pass options through to PostScript
  65.  * 20-Aug-85 (nmh) -- v1.03
  66.  * 24-Aug-85 (nmh) -- add -q option (for quiet operation).
  67.  *              changed -o option to check PostScript option
  68.  *              changed to output coordinates in TeX system (but
  69.  *              scaled to raster units) -- (0,0) at 1" in and down from
  70.  *        top left (better for use with different size paper).
  71.  *           -- v2.00
  72.  * 25-Aug-85 (nmh) -- added dictionary enclosure to Tex.ps, and output
  73.  *        suitable prolog here.
  74.  * 26-Aug-85 (nmh) -- changes to tex.ps to support Macintosh documents.
  75.  * 14-Sep-85 (nmh) -- added keyword=value decoding to \special;
  76.  * 15-Sep-85 (nmh) -- added -i file option.
  77.  * 23-Sep-85 (saj) -- added font substitution for case when font is
  78.  *              unavailable at requested mag. (a frequent occurrence
  79.  *              with some macro packages like LaTeX)
  80.  *  7-Jun-86 (hwt) -- use gf files ("pxl" survives in variable names)
  81.  *  8-Aug-86 (rkf) -- merged together the pxl and the gf versions.  Define
  82.  *              USEPXL should you want PXL files---gf is the default
  83.  *  14-Dec-87 (peterd) -- Changed sub-directory structure used by findfile.
  84.  *            Style names are used for subdirectories, not style
  85.  *            plus design size.
  86.  *            Changed font substitutions to compare <design size>
  87.  *            * <mag size>, not design and mag separately.
  88.  *            Changed all progress messages to go through Progress().
  89.  *            Changed all warning messages to go through Warning().
  90.  *            Note that Stats and Debug still use stderr.
  91.  *            Added support for font paths (multiple -a options).
  92.  *            Added support for environment variable for font path.
  93.  */
  94.  
  95. /* This version purports to drive a PostScript device (slowly) */
  96.  
  97. /**********************************************************************/
  98. /***********************  external definitions  ***********************/
  99. /**********************************************************************/
  100.  
  101. #include <stdio.h>
  102. #include <ctype.h>
  103. #include <strings.h>
  104. #include <signal.h>
  105. #include <sys/file.h>
  106. #include <sys/param.h>
  107. #include "dvi2ps.h"
  108. #include "font.h"
  109. #include "commands.h"
  110. #include "findfile.h"
  111. #include "gf.h"
  112.  
  113. /* why is this not included from c libs? */
  114. extern char *getenv();
  115.  
  116. #ifdef NOTDEF
  117. extern int  access();
  118. extern char *malloc();
  119. extern int  free();
  120. extern char *logname();
  121. #endif NOTDEF
  122.  
  123. /**********************************************************************/
  124. /************************  Global Definitions  ************************/
  125. /**********************************************************************/
  126.  
  127. /* default font area (directory) */
  128. #ifndef FONTAREA
  129. #define  FONTAREA    "/usr/local/lib/tex/fonts"
  130. #endif FONTAREA
  131.  
  132. /* name for environment variable for tex font path/directory */
  133. #ifndef ENVTEXFONTS
  134. #define ENVTEXFONTS    "TEXFONTS"
  135. #endif ENVTEXFONTS
  136.  
  137. /* default header file location */
  138. #ifndef HDRFILE
  139. #define HDRFILE        "/usr/local/lib/tex.ps"
  140. #endif HDRFILE
  141.  
  142. #ifdef apollo
  143. #ifndef SPOOLFILE
  144. #define SPOOLFILE    "/local/spool/laser/tex."
  145. #endif not SPOOLFILE
  146. #define MAXFLEN 28
  147. #endif apollo
  148.  
  149. #ifdef apollo
  150. #define  MAXOPEN     45    /* limit on number of open font files */
  151. #else !apollo
  152. #define  MAXOPEN     12    /* limit on number of open font files */
  153. #endif !apollo
  154.  
  155. #ifdef apollo       /* define for enabling of -c option (create output file) */
  156. #define CREOPT
  157. #endif apollo
  158.  
  159. #define USEGLOBALMAG 1            /* when defined, the dvi global */
  160.                     /*   magnification is applied   */
  161.     /* We can leave USEGLOBALMAG undefined when we have a limited
  162.        number of font magnifications (at 300dpi) available.  Otherwise, we
  163.        will simply complain about missing font files
  164.      */
  165. /* #undef USEGLOBALMAG */
  166.     /* define for "optimal" relative postioning, rather
  167.        than absolute.  Relative can reduce size of postcript
  168.        output 20% (and reduce print time by almost as much */
  169.  
  170. #define USERELPOS    1 
  171.  
  172. #define DEBUG   1            /* for massive printing of input */
  173.                     /* trace information; select by -d */
  174.                     /* option after filename: */
  175.                     /* dviview filename -d */
  176. #define STATS        /* to enable statistics reporting via -s option */
  177.  
  178. #define MACROS        /* use macros for some of the low level routines */
  179.  
  180. #define BINARYOPEN fopen        /* byte-oriented host version */
  181.  
  182. #define ARITHRSHIFT 1       /* define if ">>" operator is a */
  183.                     /* sign-propagating arithmetic  */
  184.                     /*   right shift */
  185.  
  186. #define  RESOLUTION      300
  187. #define  hconvRESOLUTION 300
  188. #define  vconvRESOLUTION 300
  189.  
  190. #ifdef NOTDEF
  191. #define  MAXFONTCHARS    128
  192. #define  PXLID        1001
  193. #endif NOTDEF
  194.  
  195. #define  DVIFORMAT    2
  196.  
  197. #define  STACKSIZE    100
  198. #define  STRSIZE    257
  199. #define  PATHSIZE    50
  200.  
  201. #define  NONEXISTANT    -1    /* offset for font files not found */
  202. #define  NO_FILE    (FILE *)-1
  203.  
  204. #define  TRUE        1
  205. #define  FALSE        0
  206.  
  207. /* define constants for fseek() */
  208. #define FROM_START    0
  209. #define FROM_HERE    1
  210. #define FROM_END    2
  211.  
  212. /**********************************************************************/
  213. /***********************  external definitions  ***********************/
  214. /**********************************************************************/
  215. /* macro definitions */
  216.  
  217. #define NEW(A) ((A *) malloc(sizeof(A)))
  218.  
  219. #define EQ(a,b) (strcmp(a,b)==0)
  220.  
  221.             /* output a formatted string */
  222. #define EMIT      fprintf
  223.             /* output a simple string */
  224. #define EMITS(s)  fputs(s,G_outfp)
  225.             /* output an escaped octal number */
  226. #define EMITO(c)  PutOct(c)
  227.             /* output a decimal integer */
  228. #define EMITN(n)  PutInt(n)
  229.             /* output a byte value in Hex */
  230. #define EMITH(h)  putc(*(digit+((h>>4)&0xF)),G_outfp),\
  231.           putc(*(digit+(h&0xF)),G_outfp)
  232.             /* output a single character */
  233. #define EMITC(c)  putc(c,G_outfp)
  234.             /* output a scaled X dimension */
  235. #define EMITX(x)  PutInt(PixRound(x,G_hconv))
  236.             /* output a scaled Y dimension */
  237. #define EMITY(y)  PutInt(PixRound(y,G_vconv))
  238.  
  239.             /* formatted i/o was killing us, so build some tables */
  240. char    *digit = "0123456789ABCDEF";
  241.  
  242. /* intended as replacements to NoSignExtend */
  243. /* may not be transportable */
  244. #define GET1(fp)  (int)(getc(fp))
  245. #define GET2(fp)  NoSignExtend(fp,2)
  246. #define GET3(fp)  NoSignExtend(fp,3)
  247. #define GET4(fp)  NoSignExtend(fp,4)
  248.  
  249. #ifdef NOTDEF
  250. /* may not be transportable or even work */
  251. #define GET2(fp)  ((getc(fp)<<8) | getc(fp))
  252. #define GET3(fp)  ((getc(fp)<<16) | (getc(fp)<<8) | getc(fp))
  253. #define GET4(fp)  ((getc(fp)<<24) | (getc(fp)<<16) | (getc(fp)<<8) | getc(fp))
  254. #define UNGET1(fp,ch)  fseek(fp, -1, FROM_HERE)
  255. #endif NOTDEF
  256.  
  257. #define GETN(fp,n)  NoSignExtend(fp,n)
  258. #define GETSN(fp,n)  SignExtend(fp,n)
  259.  
  260. #define UNGET1(fp,ch)  ungetc(ch,fp)
  261. #define SKIP(fp,n)  fseek(fp,n,FROM_HERE)
  262.  
  263. /*---------------------------------------------------------------------*/
  264. /* convertion to macro */
  265.  
  266. #ifdef MACROS
  267. #define PixRound(x,conv)  ((int)((x + (conv >> 1)) / conv))
  268. #define MoveDown(a)  G_v += a;
  269. #define MoveOver(b)  G_h += b;
  270. #endif MACROS
  271.  
  272. /**********************************************************************/
  273. /*************************  Global Variables  *************************/
  274. /**********************************************************************/
  275.  
  276. /* file name stuff */
  277. FILE *G_dvifp  = NULL;        /* DVI file pointer */
  278. FILE *G_outfp = NULL;        /* output file */
  279. char G_filename[STRSIZE];    /* DVI file name */
  280. char G_rootname[STRSIZE];    /* DVI filename without extension */
  281. char G_Logname[STRSIZE];    /* name of log file, if created */
  282. int  G_logging = FALSE;        /* Are we logging into a file? */
  283. FILE *G_logfp = NULL;        /* log file pointer (for errors) */
  284. char G_progname[STRSIZE];    /* this program name (dvi2ps) */
  285. int  G_quiet = FALSE;        /* for quiet operation */
  286. int  G_nowarn = FALSE;        /* don't print out warnings */
  287. long G_ppagep;            /* previous page pointer */
  288. #ifdef CREOPT
  289. int  G_create = FALSE;        /* create an output file in spool area ? */
  290. char G_outfname[STRSIZE];    /* name of output file */
  291. #endif CREOPT
  292.  
  293. /* status stuff */
  294. int  G_errenc = FALSE;        /* has an error been encountered? */
  295. int  G_ndone = 0;        /* number of pages converted */
  296.  
  297. /* measurement stuff */
  298. int  G_hconv;            /* converts DVI units to pixels - horiz. */
  299. int  G_vconv;            /* converts DVI units to pixels - vertical */
  300. int  G_h;            /* current horizontal position */
  301. int  G_hh = 0;            /* current h on device */
  302. int  G_v;            /* current vertical position */
  303. int  G_vv = 0;            /* current v on device */
  304. int  D_mag;            /* magnification(*1000) specified in preamble */
  305. int  D_num;            /* numerator specified in preamble */
  306. int  D_den;            /* denominator specified in preamble */
  307.  
  308. /* font stuff */
  309. int   G_nopen = 0;        /* number of open font files (pxl/gf) */
  310. struct open_font_list G_font_files[MAXOPEN];
  311. struct font_entry *G_prevfont=NULL;    /* font_entry pointer, previous font */
  312. struct font_entry *G_fontptr;        /* font_entry pointer, current font */
  313. struct font_entry *G_hfontptr=NULL;    /* head of font_entry pointer list */
  314. struct font_entry *G_pfontptr = NULL;    /* previous font_entry pointer */
  315.                 /* list of open font file identifiers */
  316. long  G_postambleptr;        /* Pointer to the postamble */
  317. FILE *G_fontfp;            /* font file pointer */
  318. char *G_fontpath[PATHSIZE];    /* a list of directories for fonts */
  319. int   G_fontpathsize = 0;        /* number of directories on font path */
  320.  
  321. /* command line stuff */
  322. int  CL_FirstPage = -1000000;     /* first page to print (uses count0)   */
  323. int  CL_LastPage = 1000000;       /* last page to print        */
  324. int  CL_header = TRUE;        /* copy header file to output? */
  325. int  CL_ncopies = 1;        /* number of copies to print */
  326. int  CL_nif = 0;        /* number of files to include */
  327. char *CL_Ifile[PATHSIZE];    /* files to include */
  328. int  CL_nps = 0;        /* number of PostScript commands to send */
  329. char *CL_PScmd[PATHSIZE];    /* PostScript commands to send */
  330. int  CL_Reverse = TRUE;    /* process DVI pages in reverse order ? */
  331. int  CL_usermag = 0;          /* user specified magnification */
  332. int  CL_PreLoad = TRUE;        /* preload the font descriptions? */
  333.  
  334. /* statistics stuff */
  335. #ifdef STATS
  336. int  Stats = FALSE;        /* are we reporting stats ? */
  337. int  S_nbpxl = 0;        /* # of bytes of pixel data */
  338. int  S_onbpx = 0;        /* "optimal" number of bytes of pixel data  */
  339. int  S_ndc = 0;            /* # of different characters typeset*/
  340. int  S_tnc = 0;            /* total # of chars typeset */
  341. int  S_nbpx0, S_ndc0, S_tnc0;    /* used for printing incremental changes per dvi page */
  342. #endif STATS
  343.  
  344. #ifdef DEBUG
  345. int Debug = 0;            /* print debugging info if true */
  346. #endif DEBUG
  347.  
  348. /*---------------------------------------------------------------------*/
  349.  
  350. /**********************************************************************/
  351. /*******************************  main  *******************************/
  352. /**********************************************************************/
  353.  
  354. main(argc, argv)
  355. int argc;
  356. char *argv[];
  357.  
  358. {
  359.     struct stack_entry {  /* stack entry */
  360.     int h, v, w, x, y, z;  /* what's on stack */
  361.     };
  362.  
  363.  
  364.     register int command;    /* current command */
  365.     int count[10];        /* the 10 counters at begining of each page */
  366.     long cpagep;        /* current page pointer */
  367.     int  Emitting = FALSE;    /* are we outputting typsetting instructions? */
  368.     register int i;        /* command parameter; loop index */
  369.     register int k;        /* temporary parameter */
  370.                 /* what happens on pass 0? */
  371.     int PassNo = 0;        /* which pass over DVI page? (0,1) */
  372.     int SkipMode = FALSE;    /* in skip mode flag (page not converted) */
  373.     register int sp;        /* stack pointer */
  374.     struct stack_entry stack[STACKSIZE];    /* stack */
  375.     char SpecialStr[STRSIZE];    /* "\special" strings      */
  376.     char *tchp;            /* temporary character pointer */
  377.     register int val;        /* temporary to hold command information */
  378.     register int val2;        /* temporary to hold command information */
  379.     int w;            /* current horizontal spacing (w-reg) */
  380.     int x;            /* current horizontal spacing (x-reg) */
  381.     int y;            /* current vertical spacing (y-reg) */
  382.     int z;            /* current vertical spacing (z-reg) */
  383.  
  384.     /* set program name - for error messages */
  385.     if ((tchp = rindex(argv[0],'/')) == 0) {
  386.         strcpy(G_progname, argv[0]);
  387.     } else {
  388.         strcpy(G_progname, tchp+1);
  389.     }
  390.  
  391.     /* set up default font directory on path */
  392.     G_fontpath[0] = FONTAREA;
  393.     G_fontpathsize = 1;
  394.  
  395.     /* interpret the command line */
  396.     DecodeArgs(argc,argv);
  397.  
  398. #ifdef apollo
  399.     set_sbrk_size( 2048*1024 );
  400. #endif apollo
  401.  
  402.     /* check for presence of pre-amble */
  403.     CheckPreAmble();
  404.  
  405.     /* create output file */
  406. #ifdef CREOPT
  407.     if( G_create )
  408.     G_outfp = OpenOutput();
  409.     else
  410. #endif CREOPT
  411.     G_outfp = stdout;
  412.  
  413. /* it is important that these be the very first things output !!! */
  414.  
  415.     /* copy the postscript header file to output */
  416.     if( CL_header ) {
  417.     CopyFile( HDRFILE );
  418.     }
  419.  
  420.     /* copy all included user files - from command line */
  421.     for( i=0; i<CL_nif; i++ ) {
  422.     CopyFile( CL_Ifile[i] );
  423.     }
  424.  
  425.     /* start output */
  426.     EMITS("TeXDict begin @start\n");
  427.     EMIT(G_outfp, "%%%%Title: %s\n", G_filename);
  428.     EMIT(G_outfp, "%%%%Creator: %s\n", G_progname);
  429.     EMITS("%%EndProlog\n");
  430.  
  431.     /* prefix valid PostScript options with a "@" - from command line */
  432.     for (i=0; i<CL_nps; i++) {
  433.     if( ChkOpt(CL_PScmd[i]) ) {
  434.         EMIT(G_outfp, "@%s\n", CL_PScmd[i]);
  435.     } else {
  436.         Fatal("%s is an invalid PostScript option\n", CL_PScmd[i] );
  437.     }
  438.     }
  439.  
  440.     /* multiple copies ? */
  441.     if (CL_ncopies > 1) EMIT(G_outfp, "%d @copies\n", CL_ncopies);
  442.  
  443.     /* read the pre-amble (and postamble) info */
  444.     ReadPreAmble();
  445.  
  446.     PassNo = 0;
  447.     
  448.     /* interpret the dvi file byte code commands */
  449.     while (TRUE)
  450.  
  451.     switch (command=GET1(G_dvifp))  {
  452.  
  453.     case SET1:case SET2:case SET3:case SET4:
  454.         val = GETN(G_dvifp, command-SET1+1);
  455.         if (!SkipMode) SetChar(val, command, PassNo);
  456.         break;
  457.  
  458.     case SET_RULE:
  459.         val = GET4(G_dvifp);
  460.         val2 = GET4(G_dvifp);
  461.         if (Emitting) SetRule(val, val2, TRUE);
  462.         break;
  463.  
  464.     case PUT1:case PUT2:case PUT3:case PUT4:
  465.         val = GETN(G_dvifp,command-PUT1+1);
  466.         if (!SkipMode) SetChar(val, command, PassNo);
  467.         break;
  468.  
  469.     case PUT_RULE:
  470.         val = GET4(G_dvifp);
  471.         val2 = GET4(G_dvifp);
  472.         if (Emitting) SetRule(val, val2, FALSE);
  473.         break;
  474.  
  475.     case NOP:
  476.         break;
  477.  
  478.     /* beginning of a page */
  479.     case BOP:
  480.         cpagep = ftell(G_dvifp) - 1;
  481.         for (i=0; i<=9; i++) {
  482.         count[i] = GET4(G_dvifp);
  483.         }
  484.         G_ppagep = GET4(G_dvifp);
  485.  
  486.         G_h = G_v = w = x = y = z = 0;
  487.         G_hh = G_vv = 0;
  488.         sp = 0;
  489.         G_fontptr = NULL;
  490.         G_prevfont = NULL;
  491.  
  492.         if( count[0] < CL_FirstPage || count[0] > CL_LastPage ) {
  493.         /* skip this page */
  494.         SkipMode = TRUE;
  495.         } else {
  496.         SkipMode = FALSE;
  497.         }
  498.  
  499.         Emitting = (PassNo != 0) && !SkipMode;
  500.  
  501.         if( !SkipMode ) {
  502.         if( PassNo == 0) {
  503.             EMIT(G_outfp,"%d @bop0\n", count[0]);
  504. #ifdef STATS
  505.             if( Stats ) {
  506.                 S_ndc0 = S_ndc;
  507.                 S_tnc0 = S_tnc;
  508.                 S_nbpx0 = S_nbpxl;
  509.             }
  510. #endif STATS
  511.             Progress("[%d",count[0]);
  512.         } else {
  513.             EMIT(G_outfp,"%d @bop1\n", count[0]);
  514.         }
  515.         }
  516.         break;
  517.  
  518.     /* end of this page */
  519.     case EOP:
  520.         if( !SkipMode ) {
  521.         if( PassNo == 0 ) {
  522.             /* start second pass on current page */
  523.             fseek(G_dvifp,cpagep,FROM_START);
  524.             PassNo = 1;
  525.         } else {
  526.             /* end of second pass, and of page processing */
  527.             EMITS("@eop\n");
  528. #ifdef STATS
  529.             if( Stats )
  530.             fprintf(stderr," - %d total ch,  %d diff ch,  %d pxl bytes\n",
  531.                 S_tnc-S_tnc0, S_ndc-S_ndc0, S_nbpxl-S_nbpx0);   
  532. #endif STATS
  533.             Progress("] ");
  534.             G_ndone += 1;
  535.             if ((G_ndone % 10) == 0) Progress("\n");
  536.             PassNo = 0;
  537.         }
  538.         } else {
  539.         /* just finished pass 1 (second pass) on this page */
  540.         /* next page starts in pass 0 */
  541.         PassNo = 0;
  542.         }
  543.         if( PassNo == 0 && CL_Reverse ) { 
  544.         /* go back to previous page, or done */
  545.         if( G_ppagep > 0 ) {
  546.             fseek(G_dvifp, G_ppagep, FROM_START);
  547.         } else {
  548.             AllDone();
  549.         }
  550.         }
  551.         break;
  552.  
  553.     case PUSH:
  554.         if (sp >= STACKSIZE)
  555.         Fatal("stack overflow");
  556.         stack[sp].h = G_h;
  557.         stack[sp].v = G_v;
  558.         stack[sp].w = w;
  559.         stack[sp].x = x;
  560.         stack[sp].y = y;
  561.         stack[sp].z = z;
  562.         sp++;
  563.         break;
  564.  
  565.     case POP:
  566.         --sp;
  567.         if (sp < 0)
  568.         Fatal("stack underflow");
  569.         G_h = stack[sp].h;
  570.         G_v = stack[sp].v;
  571.         w = stack[sp].w;
  572.         x = stack[sp].x;
  573.         y = stack[sp].y;
  574.         z = stack[sp].z;
  575.         break;
  576.  
  577.     case RIGHT1:case RIGHT2:case RIGHT3:case RIGHT4:
  578.         val = GETSN(G_dvifp,command-RIGHT1+1);
  579.         if (Emitting) MoveOver(val);
  580.         break;
  581.  
  582.     /* move right with the w-reg value */
  583.     case W0:
  584.         if (Emitting) MoveOver(w);
  585.         break;
  586.  
  587.     case W1:case W2:case W3:case W4:
  588.         w = GETSN(G_dvifp,command-W1+1);
  589.         if (Emitting) MoveOver(w);
  590.         break;
  591.  
  592.     /* move right with the x-reg value */
  593.     case X0:
  594.         if (Emitting) MoveOver(x);
  595.         break;
  596.  
  597.     case X1:case X2:case X3:case X4:
  598.         x = GETSN(G_dvifp,command-X1+1);
  599.         if (Emitting) MoveOver(x);
  600.         break;
  601.  
  602.     case DOWN1:case DOWN2:case DOWN3:case DOWN4:
  603.         val = GETSN(G_dvifp,command-DOWN1+1);
  604.         if (Emitting) MoveDown(val);
  605.         break;
  606.  
  607.     /* move down with the y-reg value */
  608.     case Y0:
  609.         if (Emitting) MoveDown(y);
  610.         break;
  611.  
  612.     case Y1:case Y2:case Y3:case Y4:
  613.         y = GETSN(G_dvifp,command-Y1+1);
  614.         if (Emitting) MoveDown(y);
  615.         break;
  616.  
  617.     /* move down with the z-reg value */
  618.     case Z0:
  619.         if (Emitting) MoveDown(z);
  620.         break;
  621.  
  622.     case Z1:case Z2:case Z3:case Z4:
  623.         z = GETSN(G_dvifp,command-Z1+1);
  624.         if (Emitting) MoveDown(z);
  625.         break;
  626.  
  627.     case FNT1:case FNT2:case FNT3:case FNT4:
  628.         if (!SkipMode) {
  629.         SetFontNum(GETN(G_dvifp,command-FNT1+1), Emitting);
  630.         }
  631.         break;
  632.  
  633.     case XXX1:case XXX2:case XXX3:case XXX4:
  634.         /* get the special string from the dvi file */
  635.         k = GETN(G_dvifp,command-XXX1+1);
  636.         GetBytes(G_dvifp, SpecialStr, k);
  637.         if (Emitting) DoSpecial(SpecialStr, k);
  638.         break;
  639.  
  640.     case FNT_DEF1:case FNT_DEF2:case FNT_DEF3:case FNT_DEF4:
  641.         k = GETN(G_dvifp, command-FNT_DEF1+1);
  642.         if (CL_PreLoad || HasBeenRead(k)) {
  643.         SkipFontDef();
  644.         } else {
  645.         ReadFontDef(k);
  646.         }
  647.         break;
  648.  
  649.     case PRE:
  650.         Fatal("PRE occurs within file\n");
  651.         break;
  652.  
  653.     case POST:
  654.         if (CL_Reverse) {
  655.         Warning("internal - unexpected POST in dvi file\n");
  656.         }
  657.         AllDone();
  658.         break;
  659.  
  660.     case POST_POST:
  661.         Fatal("POST_POST with no preceding POST\n");
  662.         break;
  663.  
  664.     default:
  665.         if (command >= FONT_00 && command <= FONT_63) {
  666.         if (!SkipMode) SetFontNum(command - FONT_00, Emitting);
  667.         } else if (command >= SETC_000 && command <= SETC_127) {
  668.         if (!SkipMode) SetString(command, PassNo);
  669.         } else {
  670.         Fatal("%d is an undefined DVI command\n", command);
  671.         }
  672.         break;
  673.     }
  674. }
  675.  
  676. /*-->ActualFactor*/
  677. /**********************************************************************/
  678. /**************************  ActualFactor  ****************************/
  679. /**********************************************************************/
  680.  
  681. float        /* compute the actual size factor given the approximation */
  682. ActualFactor(unmodsize)
  683. int unmodsize;        /* actually factor * 1000 */
  684. {
  685.     float realsize;    /* the actual magnification factor */
  686.  
  687.     realsize = (float)unmodsize / 1000.0;
  688.     /* a real hack to correct for rounding in some cases--rkf */
  689.     if(unmodsize==1095) realsize = 1.095445;    /*stephalf*/
  690.     else if(unmodsize==1315) realsize=1.314534;    /*stepihalf*/
  691.     else if(unmodsize==1577) realsize=1.577441;    /*stepiihalf*/
  692.     else if(unmodsize==1893) realsize=1.892929;    /*stepiiihalf*/
  693.     else if(unmodsize==2074) realsize=2.0736;    /*stepiv*/
  694.     else if(unmodsize==2488) realsize=2.48832;  /*stepv*/
  695.     else if(unmodsize==2986) realsize=2.985984;    /*stepiv*/
  696.     /* the remaining magnification steps are represented with sufficient
  697.        accuracy already */
  698.     return(realsize);
  699. }
  700.  
  701.  
  702. /*-->AllDone*/
  703. /**********************************************************************/
  704. /****************************** AllDone  ******************************/
  705. /**********************************************************************/
  706.  
  707. void
  708. AllDone()
  709. {
  710.     register struct font_entry *p;
  711.  
  712.     EMITS("@end\n");
  713.     Progress("\n");
  714.  
  715. #ifdef CREOPT
  716.     if( G_create ) {
  717.     fclose(G_outfp);
  718.     Progress("Output written on \"%s\"\n", G_outfname);
  719.     }
  720. #endif CREOPT
  721.  
  722. #ifdef STATS
  723.     if (Stats) {
  724.     fprintf(stderr,"Total-chars   diff-chars bitmap-bytes #open #close\n");
  725.     fprintf(stderr,"       #   %%       #   %%       #   %%\n");
  726.     fprintf(stderr,"-------- ---  ------ ---  ------ ---  ----- ------\n");
  727.     for (p = G_hfontptr; p != NULL; p = p->next) {
  728.         fprintf(stderr,"%8d%4d",p->ncts,(100*p->ncts + S_tnc/2)/S_tnc);
  729.         fprintf(stderr,"%8d%4d",p->ncdl,(100*p->ncdl + S_ndc/2)/S_ndc);
  730.         fprintf(stderr,"%8d%4d",p->nbpxl,(100*p->nbpxl + S_nbpxl/2)/S_nbpxl);
  731.         fprintf(stderr,"  %5d %5d",p->nopen,p->nclose);
  732.         fprintf(stderr,"  %s\n",p->psname);
  733.     }
  734.     fprintf(stderr,"\nTotal number of characters typeset: %d\n",S_tnc);
  735.     fprintf(stderr,"Number of different characters downloaded: %d\n",S_ndc);
  736.     fprintf(stderr,"Number of bytes of bitmap data downloaded: %d\n",S_nbpxl);
  737.     fprintf(stderr,"Optimal # of bytes of bitmap data: %d\n",S_onbpx);
  738.     }
  739. #endif STATS
  740.  
  741.     if (G_logging) {
  742.     if (G_logfp == NULL) {
  743.         Fatal("missing log file\n");
  744.     }
  745.     fclose(G_logfp);
  746.     Progress("Log file created\n");
  747.     }
  748.  
  749.     exit(G_errenc);
  750. }
  751.  
  752.  
  753. /*-->ChkOpt*/   /* check a user supplied option for validity */
  754. /*********************************************************************/
  755. /****************************** ChkOpt *******************************/
  756. /*********************************************************************/
  757.  
  758. #define ISOPT(s) if( EQ(str,s) ) return( TRUE )
  759.  
  760. int
  761. ChkOpt( str )
  762. char    *str;
  763. {
  764. /*    lcase(str);  doesn't work */
  765.  
  766.     ISOPT("note");      /* its a shame to build this into the program */
  767.     ISOPT("letter");
  768.     ISOPT("legal");
  769.     ISOPT("landscape");
  770.     ISOPT("manualfeed");
  771.     return( FALSE );
  772. }
  773.  
  774.  
  775. /*-->CopyFile*/
  776. /*********************************************************************/
  777. /***************************** CopyFile ******************************/
  778. /*********************************************************************/
  779. /* copy a file straight through to output */
  780.  
  781. void
  782. CopyFile(filename)
  783.     char *filename;
  784. {
  785.     register FILE *spfp;
  786.     register int ch;
  787.  
  788.     if( (spfp=fopen(filename,"r")) == NULL ) {
  789.         Warning("Unable to open file %s\n", filename );
  790.         return;
  791.     }
  792.     Progress("[%s", filename);
  793.     while ((ch = getc(spfp)) != EOF) {
  794.         EMITC(ch);
  795.     }          
  796.     fclose(spfp);
  797.     Progress("] ");
  798. }
  799.  
  800.  
  801. /*-->DecodeArgs*/
  802. /*********************************************************************/
  803. /***************************** DecodeArgs ****************************/
  804. /*********************************************************************/
  805. /* this is a pretty brain-damaged command line processor */
  806. /* but good enough for now */
  807.  
  808. void
  809. DecodeArgs( argc, argv )
  810.     int argc;
  811.     char *argv[];
  812. {
  813.     int argind;            /* argument index for flags */
  814.     char curarea[STRSIZE];    /* current file area */
  815.     char curname[STRSIZE];    /* current file name */
  816.     register char *tcp;        /* temporary character pointer */
  817.     register char *tcp1;    /* temporary character pointer */
  818.  
  819.  
  820.     /* now process command line arguments */
  821.     argind = 1;
  822.     while (argind < argc) {
  823.     tcp = argv[argind];
  824.     if (*tcp == '-') {
  825.         /* this is a command line option, which one? */
  826.         switch(*++tcp) {
  827.  
  828.         case 'a':       /* a selects different font area */
  829.             if( ++argind >= argc ) Fatal("No argument following -a\n");
  830.             if (!access(argv[argind],F_OK)) {
  831.             if (G_fontpathsize < PATHSIZE-1) {
  832.                 if (G_fontpathsize < 1) Fatal("internal - bad font path\n");
  833.                 G_fontpath[G_fontpathsize-1] = argv[argind];
  834.                 G_fontpath[G_fontpathsize] = FONTAREA;
  835.                 G_fontpathsize += 1;
  836.             }
  837.             } else {
  838.             Warning("cannot access font directory %s\n",argv[argind]);
  839.             }
  840.             break;
  841.         case 'F':       /* F selects different font area */
  842.             if( ++argind >= argc ) Fatal("No argument following -F\n");
  843.             if (!access(argv[argind],F_OK)) {
  844.             if (G_fontpathsize < PATHSIZE-1) {
  845.                 if (G_fontpathsize < 1) Fatal("internal - bad font path\n");
  846.                 G_fontpath[G_fontpathsize-1] = argv[argind];
  847.                 G_fontpath[G_fontpathsize] = FONTAREA;
  848.                 G_fontpathsize += 1;
  849.             }
  850.             } else {
  851.             Warning("cannot access font directory %s\n",argv[argind]);
  852.             }
  853.             break;
  854. #ifdef CREOPT
  855.         case 'c':       /* create an output file in spool area */
  856.             G_create = TRUE;
  857.             break;
  858. #endif CREOPT
  859. #ifdef DEBUG
  860.         case 'd':    /* d selects Debug output */
  861.             Debug = TRUE;
  862.             break;
  863. #endif DEBUG
  864.         case 'f':       /* next arg is starting pagenumber */
  865.             if( ++argind >= argc || sscanf(argv[argind], "%d", &CL_FirstPage) != 1 )
  866.             Fatal("Argument to -f is not a valid integer\n", 0);
  867.             break;
  868.  
  869.         case 'h':       /* don't copy PostScript header file through to output */
  870.             CL_header = FALSE;
  871.             break;
  872.  
  873.         case 'i':       /* next arg is a PostScript file to copy */
  874.             if( ++argind >= argc ) Fatal("No argument following -i\n");
  875.             CL_Ifile[CL_nif++] = argv[argind];
  876.             break;
  877.  
  878.         case 'l':    /* enable logging into a log file */
  879.             G_logging = TRUE;
  880.             break;
  881. #ifdef USEGLOBALMAG
  882.         case 'm':       /* specify magnification to use */
  883.             switch (*++tcp) {
  884.  
  885.             case '\0':       /* next arg is a magnification to use */
  886.             if (++argind >= argc || sscanf(argv[argind], "%d", &CL_usermag) != 1)
  887.                 Fatal("Argument to -m is not a valid integer\n", 0);
  888.             break; 
  889.             case '0': CL_usermag = 1000; break;
  890.             case 'h': CL_usermag = 1095; break;
  891.             case '1': CL_usermag = 1200; break;
  892.             case '2': CL_usermag = 1440; break;
  893.             case '3': CL_usermag = 1728; break;
  894.             case '4': CL_usermag = 2074; break;
  895.             case '5': CL_usermag = 2488; break;
  896.             default: Fatal("%c is a bad mag step\n", *tcp);
  897.             }
  898.             break;
  899. #endif USEGLOBALMAG
  900.         case 'n':       /* next arg is number of copies to print */
  901.             if( ++argind >= argc || sscanf(argv[argind], "%d", &CL_ncopies) != 1 )
  902.             Fatal("Argument to -n is not a valid integer\n", 0);
  903.             break;    
  904.  
  905.         case 'o':       /* next arg is a PostScript command to send */
  906.             if( ++argind >= argc )
  907.             Fatal("No argument following -o\n", 0);
  908.             CL_PScmd[CL_nps++] = argv[argind];
  909.             break;
  910.  
  911.         case 'p':    /* p prohibits pre-font loading */
  912.             CL_PreLoad = 0;
  913.             CL_Reverse = FALSE;    /* must then process in forward order */
  914.             break;
  915.  
  916.         case 'q':       /* quiet operation */
  917.             G_quiet = TRUE;
  918.             break;
  919.  
  920.         case 'r':       /* don't process pages in reverse order */
  921.             CL_Reverse = FALSE;
  922.             break;
  923. #ifdef STATS
  924.         case 's':       /* print some statistics */
  925.             Stats = TRUE;
  926.             break;
  927. #endif STATS
  928.         case 't':       /* next arg is ending pagenumber */
  929.             if( ++argind >= argc || sscanf(argv[argind], "%d", &CL_LastPage) != 1 )
  930.             Fatal("Argument to -t is not a valid integer\n", 0);
  931.             break;
  932.  
  933.         case 'w':       /* don't print out warnings */
  934.             G_nowarn = TRUE;
  935.             break;
  936.  
  937.         default:
  938.             Warning("%c is not a legal flag\n", *tcp);
  939.         }
  940.     } else {
  941.         /* this is not a command line option, must be the dvi file name */
  942.         if (G_dvifp != NULL) {
  943.         Warning("more than one dvi input file - ignoring \"%s\"\n",
  944.                 G_filename);
  945.         fclose(G_dvifp);
  946.         }
  947.         /* split into directory + file name */
  948.         tcp = rindex(argv[argind], '/');
  949.         /* store the directory name */
  950.         if (tcp == NULL)  {
  951.         curarea[0] = '\0';
  952.         tcp = argv[argind];
  953.         } else  {
  954.         strcpy(curarea, argv[argind]);
  955.         curarea[tcp-argv[argind]+1] = '\0';
  956.         tcp += 1;
  957.         }
  958.     
  959.         /* store the file name */
  960.         strcpy(curname, tcp);
  961.  
  962.         /* split into file name + extension */
  963.         tcp1 = rindex(tcp, '.');
  964.         if (tcp1 == NULL) {
  965.         strcpy(G_rootname, curname);
  966.         strcat(curname, ".dvi");
  967.         } else {
  968.         *tcp1 = '\0';
  969.         strcpy(G_rootname, curname);
  970.         *tcp1 = '.';
  971.         }
  972.     
  973.         /* store the full path name */
  974.         strcpy(G_filename, curarea);
  975.         strcat(G_filename, curname);
  976.     
  977.         /* open the dvi input file */
  978.         if ((G_dvifp=BINARYOPEN(G_filename,"r")) == NULL)  {
  979.         Fatal("can't open DVI file \"%s\"\n", G_filename);
  980.         }
  981.     
  982.         if (G_logging) {
  983.         strcpy(G_Logname, curname);
  984.         strcat(G_Logname, ".log");
  985.         if ((G_logfp=BINARYOPEN(G_Logname,"w+")) == NULL)  {
  986.             Fatal("can't open log file \"%s\"\n", G_Logname);
  987.         }
  988.         }
  989.     }
  990.     argind++;
  991.     }
  992.  
  993.     /* check that we got an input file to process */
  994.     if (G_dvifp == NULL)  {
  995.     Fatal("usage: %s [-a area] [-c] [-h] [-o option] [-p] [-s] [-r] [-f n] [-t n] [-m{0|h|1|2|3|4| mag}] [-a fontarea] dvifile\n\n", 
  996.         G_progname);
  997.     }
  998.  
  999.     /* now check the environment for default values */
  1000.     /* check for font area (directory/path) */
  1001.     if ((tcp = getenv(ENVTEXFONTS)) != (char *)NULL) {
  1002.     /* split out the path name components */
  1003.     /* note this code modifies the string returned by getenv() */
  1004.     while ((tcp1 = index(tcp,':')) != 0) {
  1005.         *tcp1 = '\0';
  1006.         if ((tcp == tcp1) || (*tcp == NULL)) {
  1007.         Warning("null entry in font path environment variable\n");
  1008.         continue;
  1009.         }
  1010.         if (access(tcp,F_OK)) {
  1011.         Warning("cannot access font directory %s\n",tcp);
  1012.         continue;
  1013.         }
  1014.         if (G_fontpathsize < PATHSIZE-1) {
  1015.         if (G_fontpathsize < 1) Fatal("internal - bad font path\n");
  1016.         G_fontpath[G_fontpathsize-1] = tcp;
  1017.         G_fontpathsize += 1;
  1018.         } else {
  1019.         Warning("too many entries in font path environment variable, ignoring %s\n",tcp);
  1020.         }
  1021.         tcp = tcp1 + 1;
  1022.     }
  1023.     if ((tcp == tcp1) || (*tcp == NULL)) {
  1024.         Warning("null entry in font path environment variable\n");
  1025.     } else if (access(tcp,F_OK)) {
  1026.         Warning("cannot access font directory %s\n",tcp);
  1027.     } else {
  1028.         if (G_fontpathsize < PATHSIZE-1) {
  1029.         if (G_fontpathsize < 1) Fatal("internal - bad font path\n");
  1030.         G_fontpath[G_fontpathsize-1] = tcp;
  1031.         G_fontpathsize += 1;
  1032.         } else {
  1033.         Warning("too many entries in font path environment variable, ignoring %s\n",tcp);
  1034.         }
  1035.     }
  1036.     G_fontpath[G_fontpathsize-1] = FONTAREA;
  1037.     }
  1038. }
  1039.  
  1040.  
  1041. /*-->DoConv*/
  1042. /*********************************************************************/
  1043. /********************************  DoConv  ***************************/
  1044. /*********************************************************************/
  1045.  
  1046. int DoConv(num, den, convResolution)
  1047. {
  1048.     register float conv;
  1049.     conv = ((float)num/(float)den) * 
  1050. #ifdef USEGLOBALMAG
  1051. /*    ActualFactor(D_mag) * why was this in as Actual Factor?  jls */
  1052.     ((float) D_mag/1000.0) *
  1053. #endif USEGLOBALMAG
  1054.     ((float)convResolution/254000.0);
  1055.     return((int) (1.0 / conv + 0.5));
  1056. }
  1057.  
  1058.  
  1059. /*-->DoSpecial*/
  1060. /*********************************************************************/
  1061. /*****************************  DoSpecial  ***************************/
  1062. /*********************************************************************/
  1063.  
  1064. typedef enum {None, String, Integer, Number, Dimension} ValTyp;
  1065.  
  1066. typedef struct {
  1067.     char    *Key;       /* the keyword string */
  1068.     char    *Val;       /* the value string */
  1069.     ValTyp  vt;         /* the value type */
  1070.     union {     /* the decoded value */
  1071.         int  i;
  1072.         float n;
  1073.         } v;
  1074.     } KeyWord;
  1075.  
  1076. typedef struct {
  1077.     char    *Entry;
  1078.     ValTyp  Type;
  1079.     } KeyDesc;
  1080.  
  1081. #define PSFILE 0
  1082. KeyDesc KeyTab[] = {{"psfile", String},
  1083.             {"hsize", Dimension},
  1084.             {"vsize", Dimension},
  1085.             {"hoffset", Dimension},
  1086.             {"voffset", Dimension},
  1087.             {"hscale", Number},
  1088.             {"vscale", Number}};
  1089.  
  1090. #define NKEYS (sizeof(KeyTab)/sizeof(KeyTab[0]))
  1091.  
  1092. /*-->DoSpecial*/
  1093. /*********************************************************************/
  1094. /*****************************  DoSpecial  ***************************/
  1095. /*********************************************************************/
  1096. /* interpret a \special command, made up of keyword=value pairs */
  1097.  
  1098. void
  1099. DoSpecial( str, n )
  1100.     char    *str;
  1101.     int n;
  1102.     char spbuf[STRSIZE]; 
  1103.     char *sf = NULL;
  1104.     KeyWord k;
  1105.     int i;
  1106.  
  1107.     str[n] = '\0';
  1108.     spbuf[0] = '\0';
  1109.  
  1110.     SetPosn(G_h, G_v);
  1111.     EMITS("@beginspecial\n");
  1112.  
  1113.     /* get all keyword-value pairs */
  1114.     while( (str=GetKeyStr(str,&k)) != NULL ) {
  1115.     /* for compatibility, single words are taken as file names */
  1116.     if( k.vt == None && access(k.Key,F_OK) == 0) {
  1117.         if (sf) {
  1118.         Warning("More than one \\special file name given. %s ignored", sf );
  1119.         }
  1120.         strcpy(spbuf, k.Key);
  1121.         sf = spbuf;
  1122.     } else if( GetKeyVal( &k, KeyTab, NKEYS, &i ) && i != -1 ) {
  1123.         if( i == PSFILE ) {
  1124.         if (sf) {
  1125.             Warning("More than one \\special file name given. %s ignored", sf );
  1126.         }
  1127.         strcpy(spbuf, k.Val);
  1128.         sf = spbuf;
  1129.         } else {
  1130.         /* the keywords are simply output as PS procedure calls */
  1131.         EMIT(G_outfp, "%f @%s\n", k.v.n, KeyTab[i].Entry);
  1132.         }
  1133.     } else {
  1134.         Warning("Invalid keyword or value in \\special - \"%s\" ignored", k.Key );
  1135.     }
  1136.     }
  1137.  
  1138.     EMITS("@setspecial\n");
  1139.  
  1140.     if (sf) {
  1141.     CopyFile( sf );
  1142.     } else {
  1143.     Warning("No special file name provided.");
  1144.     }
  1145.  
  1146.     EMITS("@endspecial\n");
  1147. }
  1148.  
  1149.  
  1150. /*-->EmitCharBitMap*/
  1151. /**********************************************************************/
  1152. /************************  EmitCharBitMap  ****************************/
  1153. /**********************************************************************/
  1154. /* output a character bitmap */
  1155.  
  1156. void
  1157. EmitCharBitMap(ch, ce)
  1158.     int ch;
  1159.     register struct char_entry *ce;
  1160. {
  1161.     register unsigned char *sl;
  1162.     register struct font_entry *fontp;
  1163. #ifdef USEPXL
  1164.     int i;
  1165.     register int j;
  1166.     register int cc;
  1167.     int nbpl, nwpl;
  1168. #else not USEPXL
  1169.     register int cc;
  1170.     register int i;
  1171.     int nbpl;        /* number of bytes per line of bitmap */
  1172. #endif USEPXL
  1173.     float cw;    /* char width, in "dots" */
  1174.             /* we rely on PostScript maintaining sufficient accuracy */
  1175.  
  1176.     /* sanity check */
  1177.     fontp = G_fontptr;
  1178.     if (fontp == NULL) {
  1179.         Fatal("internal - null pointer in EmitCharBitMap()\n");
  1180.     }
  1181.  
  1182.     /* Output in PostScript coord system (y +ive up, x +ive right)
  1183.        (0,0) of char bitmap at lower left.  Output scan lines
  1184.        from bottom to top */
  1185.  
  1186.     /* open font dict before first char */
  1187.     if (fontp->ncdl == 0) {
  1188.         EMIT(G_outfp,"[ %d ] /%s @newfont\n",
  1189.         fontp->font_mag,fontp->psname);
  1190.     }
  1191.  
  1192.     /* because this isn't done on pass 0 */
  1193.     if (fontp != G_prevfont) {
  1194.         EMIT(G_outfp,"%s @sf\n", fontp->psname);
  1195.         G_prevfont = fontp;
  1196.     }
  1197.  
  1198.     /* start the bitmap */
  1199.     EMITS("[<");
  1200.     cc = 2;
  1201.  
  1202. #ifdef USEPXL
  1203.     nbpl = (ce->width + 7) >> 3;
  1204.     nwpl = (ce->width + 31) >> 5;
  1205.     for(i = ce->height-1;  i >= 0;  i--) {
  1206.         sl = (unsigned char *)(ce->where.address.pixptr + i*nwpl);
  1207.         for(j = 0;  j < nbpl;  j++, sl++) {
  1208.             if( cc > 100 ) {
  1209.                 EMITS("\n  ");   cc = 2;
  1210.             }
  1211.             EMITH(*sl);
  1212.             cc += 2;
  1213.         }
  1214.     }
  1215. #else not USEPXL
  1216.     /* assume we just called gf_readbits() */
  1217.     nbpl = (gf_num_cols + 7) >> 3;
  1218.     for(i=0, sl=gf_bits; i<gf_num_bytes; i++, sl++) {
  1219.         if (cc > 100) {
  1220.             EMITS("\n  ");
  1221.             cc = 2;
  1222.         }
  1223.         EMITH(*sl);
  1224.         cc += 2;
  1225.     }
  1226. #endif USEPXL
  1227.  
  1228.     /* compute character width */
  1229.     cw = (float)ce->tfmw / (float)G_hconv;
  1230.  
  1231. #ifdef USEPXL
  1232.     EMIT(G_outfp,"> %d %d %d %d %.3f] %d @dc\n", 
  1233.          nbpl<<3, ce->height, ce->xOffset,
  1234.          (((int)ce->height)-ce->yOffset)-1, cw, ch);
  1235. #else not USEPXL
  1236.     EMIT(G_outfp,"> %d %d %d %d %.3f] %d @dc\n", 
  1237.          nbpl<<3, gf_num_rows, gf_x_offset, gf_y_offset, cw, ch);
  1238. #endif USEPXL
  1239.  
  1240.     /* one more character down loaded */
  1241.     fontp->ncdl += 1;
  1242.  
  1243. #ifdef STATS
  1244. #ifdef USEPXL
  1245.     S_nbpxl += nbpl*ce->height;
  1246.     fontp->nbpxl += nbpl*ce->height;
  1247.     S_onbpx += (ce->width*ce->height + 7) >> 3;
  1248. #else not USEPXL
  1249.     S_nbpxl += nbpl*gf_num_rows;
  1250.     fontp->nbpxl += nbpl*gf_num_rows;
  1251.     S_onbpx += (gf_num_cols*gf_num_rows + 7) >> 3;
  1252. #endif USEPXL
  1253.     S_ndc += 1;
  1254. #endif STATS
  1255. }
  1256.  
  1257. /*-->Fatal*/
  1258. /**********************************************************************/
  1259. /******************************  Fatal  *******************************/
  1260. /**********************************************************************/
  1261. /* emit a message and die */
  1262. /* VARARGS1 for lint */
  1263.  
  1264. void
  1265. Fatal(fmt, a, b, c, d, e, f)        /* issue a fatal error message */
  1266.     char *fmt;                /* format */
  1267.     char *a, *b, *c, *d, *e, *f;    /* arguments */
  1268. {
  1269.     /* always print fatal error message */
  1270.     fprintf(stderr, "\n%s: FATAL--", G_progname);
  1271.     fprintf(stderr, fmt, a, b, c, d, e, f);
  1272.     fprintf(stderr, "\n");
  1273.  
  1274.     /* if logging to a file, print again there */
  1275.     if (G_logging) {
  1276.     if (G_logfp == NULL) {
  1277.         fprintf(stderr,"\n%s: FATAL--missing log file\n",G_progname);
  1278.     }
  1279.     fprintf(G_logfp, "\n%s: FATAL--", G_progname);
  1280.     fprintf(G_logfp, fmt, a, b, c, d, e, f);
  1281.     fprintf(G_logfp, "\n");
  1282.     }
  1283.  
  1284. #ifdef CREOPT
  1285.     /* close and delete the output file */
  1286.     if (G_create && G_outfp != NULL) {
  1287.     fclose(G_outfp);
  1288.     unlink(G_outfname);
  1289.     }
  1290. #endif CREOPT
  1291.     exit(1);
  1292. }
  1293.  
  1294. /*-->GetBytes*/
  1295. /**********************************************************************/
  1296. /*****************************  GetBytes  *****************************/
  1297. /**********************************************************************/
  1298. /* get n bytes from file fp, store string in cp */
  1299.  
  1300. void
  1301. GetBytes(fp, cp, n)
  1302.     register FILE *fp;    /* file pointer     */
  1303.     register char *cp;    /* character pointer */
  1304.     register int n;    /* number of bytes  */
  1305. {
  1306.     while (n--) {
  1307.     *cp++ = getc(fp);
  1308.     }
  1309. }
  1310.  
  1311. /*-->GetKeyStr*/
  1312. /**********************************************************************/
  1313. /*****************************  GetKeyStr  ****************************/
  1314. /**********************************************************************/
  1315.  
  1316.     /* extract first keyword-value pair from string (value part may be null)
  1317.      * return pointer to remainder of string
  1318.      * return NULL if none found
  1319.      */
  1320.  
  1321. char    KeyStr[STRSIZE];
  1322. char    ValStr[STRSIZE];
  1323.  
  1324. char *GetKeyStr( str, kw )
  1325. char    *str;
  1326. KeyWord *kw;
  1327. {
  1328.     char *s, *k, *v, t;
  1329.  
  1330.     if( !str ) return( NULL );
  1331.  
  1332.     for( s=str; *s == ' '; s++ ) ;      /* skip over blanks */
  1333.     if( *s == '\0' ) return( NULL );
  1334.  
  1335.     for( k=KeyStr;      /* extract keyword portion */
  1336.          *s != ' ' && *s != '\0' && *s != '='; 
  1337.          *k++ = *s++ ) ;
  1338.     *k = '\0';
  1339.     kw->Key = KeyStr;
  1340.     kw->Val = v = NULL;
  1341.     kw->vt = None;
  1342.  
  1343.     for( ; *s == ' '; s++ ) ;           /* skip over blanks */
  1344.     if( *s != '=' )     /* look for "=" */
  1345.         return( s );
  1346.  
  1347.     for( s++ ; *s == ' '; s++ ) ;       /* skip over blanks */
  1348.     if( *s == '\'' || *s == '\"' )      /* get string delimiter */
  1349.         t = *s++;
  1350.     else
  1351.         t = ' ';
  1352.     for( v=ValStr;      /* copy value portion up to delim */
  1353.          *s != t && *s != '\0';
  1354.          *v++ = *s++ ) ;
  1355.     if( t != ' ' && *s == t ) s++;
  1356.     *v = '\0';
  1357.     kw->Val = ValStr;
  1358.     kw->vt = String;
  1359.  
  1360.     return( s );
  1361. }
  1362.  
  1363. /*-->GetKeyVal*/
  1364. /**********************************************************************/
  1365. /*****************************  GetKeyVal  ****************************/
  1366. /**********************************************************************/
  1367.  
  1368.     /* get next keyword-value pair
  1369.      * decode value according to table entry
  1370.      */
  1371.  
  1372. int GetKeyVal( kw, tab, nt, tno)
  1373. KeyWord *kw; 
  1374. KeyDesc tab[];
  1375. int     nt;
  1376. int     *tno;
  1377. {
  1378.     int i;
  1379.     char c = '\0';
  1380.  
  1381.     *tno = -1;
  1382.  
  1383.     for(i=0; i<nt; i++)
  1384.         if( IsSame(kw->Key, tab[i].Entry) ) {
  1385.             *tno = i;
  1386.             switch( tab[i].Type ) {
  1387.                 case None: 
  1388.                     if( kw->vt != None ) return( FALSE );
  1389.                     break;
  1390.                 case String:
  1391.                     if( kw->vt != String ) return( FALSE );
  1392.                     break;
  1393.                 case Integer:
  1394.                     if( kw->vt != String ) return( FALSE );
  1395.                     if( sscanf(kw->Val,"%d%c", &(kw->v.i), &c) != 1
  1396.                         || c != '\0' ) return( FALSE );
  1397.                     break;
  1398.                 case Number:
  1399.                 case Dimension:
  1400.                     if( kw->vt != String ) return( FALSE );
  1401.                     if( sscanf(kw->Val,"%f%c", &(kw->v.n), &c) != 1
  1402.                         || c != '\0' ) return( FALSE );
  1403.                     break;
  1404.                 }
  1405.             kw->vt = tab[i].Type;
  1406.             return( TRUE );
  1407.             }
  1408.  
  1409.     return( TRUE );
  1410. }
  1411.  
  1412. /*-->HasBeenRead*/
  1413. /**********************************************************************/
  1414. /***************************  HasBeenRead  ****************************/
  1415. /**********************************************************************/
  1416.  
  1417. int
  1418. HasBeenRead(fontnum)
  1419.     int fontnum;
  1420. {
  1421.     register struct font_entry *ptr;
  1422.  
  1423.     /* search font entry list for this font number (from dvi file) */
  1424.     ptr = G_hfontptr;
  1425.     while ((ptr != NULL) && (ptr->dvi_fnum != fontnum)) {
  1426.     ptr = ptr->next;
  1427.     }
  1428.     return( ptr != NULL );
  1429. }
  1430.  
  1431. /*-->IsSame*/
  1432. /**********************************************************************/
  1433. /*******************************  IsSame  *****************************/
  1434. /**********************************************************************/
  1435. /* compare strings, ignore case */
  1436.  
  1437. int IsSame(a, b)
  1438. char *a, *b;
  1439. {
  1440.     for( ; *a != '\0'; ) {
  1441.         if( tolower(*a++) != tolower(*b++) ) return( FALSE );
  1442.     }
  1443.     return( *a == *b ? TRUE : FALSE );
  1444. }
  1445.  
  1446. /*-->MoveDown*/
  1447. /**********************************************************************/
  1448. /****************************  MoveDown  ******************************/
  1449. /**********************************************************************/
  1450.  
  1451. #ifndef MACROS
  1452. void
  1453. MoveDown(a)
  1454. int a;
  1455. {
  1456.     G_v += a;
  1457. }
  1458. #endif MACROS
  1459.  
  1460. /*-->MoveOver*/
  1461. /**********************************************************************/
  1462. /****************************  MoveOver  ******************************/
  1463. /**********************************************************************/
  1464.  
  1465. #ifndef MACROS
  1466. void
  1467. MoveOver(b)
  1468. int b;
  1469. {
  1470.     G_h += b;
  1471. }
  1472. #endif MACROS
  1473.  
  1474. /*-->NoSignExtend*/
  1475. /**********************************************************************/
  1476. /***************************  NoSignExtend  ***************************/
  1477. /**********************************************************************/
  1478.  
  1479. int
  1480. NoSignExtend(fp, n)    /* return n byte quantity from file fd */
  1481. register FILE *fp;    /* file pointer    */
  1482. register int n;        /* number of bytes */
  1483.  
  1484. {
  1485.     register int x;    /* number being constructed */
  1486.  
  1487.     x = 0;
  1488.     while (n--)  {
  1489.     x <<= 8;
  1490.     x |= getc(fp);
  1491.     }
  1492.     return(x);
  1493. }
  1494.  
  1495. /*-->OpenFontFile*/
  1496. /**********************************************************************/
  1497. /************************** OpenFontFile  *****************************/
  1498. /**********************************************************************/
  1499. /***********************************************************************
  1500.     The original version of this dvi driver reopened the font file  each
  1501.     time the font changed, resulting in an enormous number of relatively
  1502.     expensive file  openings.   This version  keeps  a cache  of  up  to
  1503.     MAXOPEN open files,  so that when  a font change  is made, the  file
  1504.     pointer, G_fontfp, can  usually be  updated from the  cache.  When  the
  1505.     file is not found in  the cache, it must  be opened.  In this  case,
  1506.     the next empty slot  in the cache  is assigned, or  if the cache  is
  1507.     full, the least used font file is closed and its slot reassigned for
  1508.     the new file.  Identification of the least used file is based on the
  1509.     counts of the number  of times each file  has been "opened" by  this
  1510.     routine.  On return, the file pointer is always repositioned to  the
  1511.     beginning of the file.
  1512.  
  1513. ***********************************************************************/
  1514.  
  1515. void
  1516. OpenFontFile()
  1517. {
  1518.     register struct font_entry *fontp;
  1519.     register struct open_font_list *openp;
  1520.     register struct font_entry *least_fontp;
  1521.     register struct open_font_list *least_openp;
  1522.     register FILE *fid;
  1523.  
  1524.  
  1525. #ifdef DEBUG
  1526.     if (Debug) printf("Open Font file\n");
  1527. #endif DEBUG
  1528.     /* check for consistency here */
  1529.     if (G_fontptr == NULL) {
  1530.     Fatal("internal - null font structure pointer in OpenFontFile()\n");
  1531.     }
  1532.  
  1533. #ifdef STATS
  1534.     /* count number of times open attempted */
  1535.     G_fontptr->nopen += 1;
  1536. #endif STATS
  1537.  
  1538.     /* G_pfontptr is last font "OpenFontFile"'ed */
  1539.     if (G_pfontptr == G_fontptr) {
  1540.     /* we need not have been called */
  1541.     return;
  1542.     }
  1543.  
  1544.     /* check if this font file is already open */
  1545.     fontp = G_fontptr;
  1546.     if ((openp = fontp->open_font_ptr) == NULL) {
  1547.     /* this file is not open, so open it */
  1548.     if (G_nopen < MAXOPEN-1) {
  1549.         /* still open slots, so use one */
  1550.         openp = &G_font_files[G_nopen];
  1551.         G_nopen += 1;
  1552. #ifdef DEBUG
  1553.         if (Debug) fprintf(stderr,"opening (new slot) font file %s\n",fontp->name);
  1554. #endif DEBUG
  1555.     } else {
  1556. #ifdef DEBUG
  1557.         if (Debug) fprintf(stderr,"opening (find slot) font file %s\n",fontp->name);
  1558. #endif DEBUG
  1559.         /* find least used, close it, and reuse slot */
  1560.         /* list full -- find least used file, */
  1561.         /* close it, and reuse slot for new file */
  1562.         least_openp = &G_font_files[0];
  1563.         for (openp = &G_font_files[G_nopen-1]; openp > &G_font_files[0]; openp -= 1) {
  1564.         if (least_openp->use_count > openp->use_count) least_openp = openp;
  1565.         }
  1566.         openp = least_openp;
  1567.         if (openp->pixel_file_id != NO_FILE) {
  1568.         fid = openp->pixel_file_id;
  1569.         if ((least_fontp = openp->font_entry_ptr) == NULL) {
  1570.             Fatal("internal - bad open font in OpenFontFile()\n");
  1571.         }
  1572.         /* mark as closed */
  1573.         least_fontp->font_file_id = NULL;
  1574.         least_fontp->open_font_ptr = NULL;
  1575. #ifdef STATS
  1576.         /* count number of times open attempted */
  1577.         G_fontptr->nclose += 1;
  1578.         if (Stats) fprintf(stderr,"closed font file %s\n",least_fontp->name);
  1579. #endif STATS
  1580.         fclose( fid );
  1581.  
  1582.         }
  1583.     }
  1584.     if ((G_fontfp=BINARYOPEN(fontp->name,"r")) == NULL) {
  1585.         Warning("cannot open font file %s\n",fontp->name);
  1586.         G_fontfp = NO_FILE;
  1587.     }
  1588. #ifdef STATS
  1589.     else {
  1590.         if (Stats) fprintf(stderr,"opened font file %s\n",fontp->name);
  1591.     }
  1592. #endif STATS
  1593.     /* initialize this entry in open font file list */
  1594.     openp->pixel_file_id = G_fontfp;
  1595.     openp->font_entry_ptr = fontp;
  1596.     openp->use_count = 0;
  1597.     fontp->font_file_id = G_fontfp;    /* set file identifier */
  1598.     fontp->open_font_ptr = openp;    /* open file id */
  1599.     } else {
  1600.     /* this file is already open */
  1601.     if ((G_fontfp = openp->pixel_file_id) != NO_FILE) {
  1602.         /* is this necessary? */
  1603.         /* reposition to start of file */
  1604.         fseek(G_fontfp,(long)0,FROM_START);
  1605.     } else {
  1606.         Warning("internal - bad font file pointer - OpenFontFile()\n");
  1607.     }
  1608.     }
  1609.  
  1610.     /* have a new font file */
  1611.     G_fontptr = fontp;
  1612.     G_pfontptr = fontp;            /* make previous = current font */
  1613.     openp->use_count += 1;        /* update reference count */
  1614. #ifndef USEPXL
  1615.     gf_infile = G_fontfp;            /* used in gf reader */
  1616.     gf_filename = G_fontptr->name;        /* used in gf reader */
  1617. #endif USEPXL
  1618. }
  1619.  
  1620. #ifdef CREOPT
  1621. /*-->OpenOutput*/
  1622. /**********************************************************************/
  1623. /*************************** OpenOutput *******************************/
  1624. /**********************************************************************/
  1625. /* generate a unique file name and open it */
  1626. /* this is only for creating spool files, not general output files */
  1627.  
  1628. FILE*
  1629. OpenOutput()
  1630. {
  1631.     FILE*   fp;
  1632.     long t;
  1633.     int  n = 0;
  1634.     char *p, *pp, b[256];
  1635.     int nd;
  1636.  
  1637.     time( &t );
  1638.     t = t % 100000;
  1639.     strcpy( G_outfname, SPOOLFILE );
  1640.     sprintf( b, "%s.%s.%x", logname(), G_rootname, t );
  1641.     if( (nd=strlen(b)-MAXFLEN) > 0 ) {
  1642.            for(pp=(p=rindex(b,'.')); p && *p != '\0'; *(pp-nd) = *p++, pp++) ;
  1643.            *(pp-nd) = '\0';
  1644.     }
  1645.     strcat( G_outfname, b );
  1646.  
  1647.     while( access(G_outfname,F_OK) == 0 ) {
  1648.         n += 1;
  1649.         if( n > 10 ) 
  1650.             Fatal("Unable to create a unique output file name: %s\n", G_outfname );
  1651.         strcpy( G_outfname, SPOOLFILE );
  1652.         sprintf( b, "%s.%s.%x.%d", logname(), G_rootname, t, n );
  1653.         if( (nd=strlen(b)-MAXFLEN) > 0 ) {
  1654.             for(pp=(p=rindex(b,'.')); p && *p != '\0'; *(pp-nd) = *p++, pp++) ;
  1655.             *(pp-nd) = '\0';
  1656.             }
  1657.         strcat( G_outfname, b );
  1658.         }
  1659.  
  1660.     if( (fp=fopen(G_outfname,"w")) == NULL )
  1661.         Fatal("Unable to create output file: %s\n", G_outfname);
  1662.  
  1663.     return( fp );
  1664. }
  1665. #endif CREOPT
  1666.  
  1667. /*-->PixRound*/
  1668. /**********************************************************************/
  1669. /*****************************  PixRound  *****************************/
  1670. /**********************************************************************/
  1671.  
  1672. #ifndef MACROS
  1673. int
  1674. PixRound(x, conv)    /* return rounded number of pixels */
  1675. register int x;        /* in DVI units     */
  1676. int conv;        /* conversion factor */
  1677. {
  1678.     return((int)((x + (conv >> 1)) / conv));
  1679. }
  1680. #endif MACROS
  1681.  
  1682. /*-->PutInt*/
  1683. /**********************************************************************/
  1684. /*****************************  PutInt  *******************************/
  1685. /**********************************************************************/
  1686. /* output an integer followed by a space */
  1687. /* could we put this number out in hex to make this faster? */
  1688.  
  1689. void
  1690. PutInt(num)
  1691.     register int num;
  1692. {
  1693.     char buf[10];
  1694.     register char *b;
  1695.  
  1696.     if (num == 0) {
  1697.     EMITC('0'); 
  1698.     } else {
  1699.     if (num < 0) {
  1700.         EMITC('-');
  1701.         num = -num;
  1702.     }
  1703.     
  1704.     for (b=buf;  num>0; ) {
  1705.         *b++ = digit[num%10];
  1706.         num /= 10;
  1707.     }
  1708.     
  1709.     while (b>buf) {
  1710.         EMITC(*--b);
  1711.     }
  1712.     }
  1713.  
  1714.     EMITC(' ');
  1715. }
  1716.  
  1717. /*-->PutOct*/
  1718. /**********************************************************************/
  1719. /*****************************  PutOct  *******************************/
  1720. /**********************************************************************/
  1721.  
  1722. void
  1723. PutOct(num)           /* output an 3 digit octal number preceded by a "\" */
  1724. register int num;
  1725. {      
  1726.     EMITC( '\\' ); 
  1727.     EMITC( digit[(num&0300)>>6] );
  1728.     EMITC( digit[(num&0070)>>3] ); 
  1729.     EMITC( digit[num&0007] );
  1730. }
  1731.  
  1732. /*-->GetFontDef*/
  1733. /**********************************************************************/
  1734. /**************************** GetFontDef  *****************************/
  1735. /**********************************************************************/
  1736. /***********************************************************************
  1737.    Read the font  definitions as they  are in the  postamble of the  DVI
  1738.    file.
  1739. ***********************************************************************/
  1740.  
  1741. void
  1742. GetFontDef()
  1743. {
  1744.     register int byte;
  1745.  
  1746.     while (((byte = GET1(G_dvifp)) >= FNT_DEF1) &&
  1747.     (byte <= FNT_DEF4)) {
  1748.     switch (byte) {
  1749.     case FNT_DEF1:
  1750.         ReadFontDef (GET1(G_dvifp));
  1751.         break;
  1752.     case FNT_DEF2:
  1753.         ReadFontDef (GET2(G_dvifp));
  1754.         break;
  1755.     case FNT_DEF3:
  1756.         ReadFontDef (GET3(G_dvifp));
  1757.         break;
  1758.     case FNT_DEF4:
  1759.         ReadFontDef (GET4(G_dvifp));
  1760.         break;
  1761.     default:
  1762.         Fatal ("Bad byte value in font defs - DVI post-amble");
  1763.         break;
  1764.     }
  1765.     }
  1766.     if (byte != POST_POST) {
  1767.     Fatal ("POST_POST missing after font defs - DVI post-amble");
  1768.     }
  1769. }
  1770.  
  1771. /*-->ReadFontDef*/
  1772. /**********************************************************************/
  1773. /****************************  ReadFontDef  ***************************/
  1774. /**********************************************************************/
  1775. /* read a font definition out of the dvi file */
  1776. /* then go find the font file (pxl or gf) */
  1777. /* read a font definition out of the font file (pxl or gf) */
  1778.  
  1779. int
  1780. ReadFontDef(fontnum)
  1781.     int fontnum;        /* font number */
  1782. {
  1783.     int i;
  1784.     register struct font_entry *tfontptr;    /* temp font_entry pointer */
  1785.     register struct char_entry *tcharptr;    /* temp char_entry pointer */
  1786.     int nmag;
  1787.     char nname[STRSIZE];
  1788.  
  1789.     /* check to see if this font has already been read in */
  1790.     /* this was a bug in the last version */
  1791.     /* linear search of font entry list */
  1792.     tfontptr = G_hfontptr;
  1793.     while ((tfontptr != NULL) && (tfontptr->dvi_fnum != fontnum)) {
  1794.     tfontptr = tfontptr->next;
  1795.     }
  1796.     if (tfontptr != NULL) {
  1797.     /* we found this font, already read */
  1798. #ifdef STATS
  1799.     if (Stats) fprintf(stderr,"re-read font file %s\n",tfontptr->name);
  1800. #endif STATS
  1801.     G_fontptr = tfontptr;
  1802.     return;
  1803.     }
  1804.  
  1805.     /* allocate a new font entry */
  1806.     if ((tfontptr = NEW(struct font_entry)) == NULL) {
  1807.     Fatal("can't malloc space for font_entry");
  1808.     }
  1809.  
  1810.     /* link this entry into list (at head) */
  1811.     tfontptr->next = G_hfontptr;
  1812.     G_fontptr = G_hfontptr = tfontptr;
  1813.  
  1814.     /* initialize the new entry */
  1815.     tfontptr->font_file_id = NULL;    /* this font file not open yet */
  1816.     tfontptr->open_font_ptr = NULL;    /* this font file not open yet */
  1817.     tfontptr->ncdl = 0;            /* # chars downloaded */
  1818. #ifdef STATS
  1819.     tfontptr->nbpxl = 0;
  1820.     tfontptr->ncts = 0;
  1821.     tfontptr->nopen = 0;
  1822.     tfontptr->nclose = 0;
  1823. #endif STATS
  1824.  
  1825.     /* get font info from dvi file */
  1826.     tfontptr->dvi_fnum = fontnum;    /* font number */
  1827.     tfontptr->dvi_check = GET4(G_dvifp);    /* checksum */
  1828.     tfontptr->dvi_s = GET4(G_dvifp);    /* space size */
  1829.     tfontptr->dvi_d = GET4(G_dvifp);    /* design size */
  1830.     tfontptr->dvi_alen = GET1(G_dvifp);    /* area length for font name */
  1831.     tfontptr->dvi_nlen = GET1(G_dvifp);    /* device length */
  1832.  
  1833.     /* get font name string - according to dvi file (no mag) */
  1834.     /* note that this also gets the dvi area/directory */
  1835.     /* which is usually not present, but could be a bug */
  1836.     GetBytes(G_dvifp, tfontptr->dvi_name, tfontptr->dvi_alen+tfontptr->dvi_nlen);
  1837.     tfontptr->dvi_name[tfontptr->dvi_alen+tfontptr->dvi_nlen] = '\0';
  1838.  
  1839.     tfontptr->font_space = tfontptr->dvi_s/6;    /* never used */
  1840.  
  1841. #ifdef USEPXL
  1842. #ifdef USEGLOBALMAG
  1843.     tfontptr->font_mag = (int)((
  1844.     ActualFactor((int)
  1845.         (((float)tfontptr->dvi_s/(float)tfontptr->dvi_d)*1000.0 + 0.5)
  1846.         )
  1847.     * ActualFactor(D_mag) * (float)RESOLUTION * 5.0) + 0.5);
  1848. #else not USEGLOBALMAG
  1849.     tfontptr->font_mag = (int)((
  1850.     ActualFactor((int)
  1851.         (((float)tfontptr->dvi_s/(float)tfontptr->dvi_d)*1000.0 + 0.5)
  1852.         )
  1853.     * (float)RESOLUTION * 5.0) + 0.5);
  1854. #endif USEGLOBALMAG
  1855. #else not USEPXL
  1856. #ifdef USEGLOBALMAG
  1857.     tfontptr->font_mag = (int)((
  1858.     ActualFactor((int)
  1859.         (((float)tfontptr->dvi_s/(float)tfontptr->dvi_d)*1000.0 + 0.5)
  1860.         )
  1861.     * ActualFactor(D_mag) * (float)RESOLUTION) + 0.5);
  1862. #else not USEGLOBALMAG
  1863.     tfontptr->font_mag = (int)((
  1864.     ActualFactor((int)
  1865.         (((float)tfontptr->dvi_s/(float)tfontptr->dvi_d)*1000.0 + 0.5)
  1866.         )
  1867.     * (float)RESOLUTION) + 0.5);
  1868. #endif USEGLOBALMAG
  1869. #endif USEPXL
  1870.  
  1871.     /* for debugging */
  1872. #ifdef DEBUG
  1873.     if (Debug) {
  1874.     fprintf(stderr,"ReadFontDef k=%d c=%d s=%d d=%d a=%d l=%d n=%s mag=%d gmag=%d\n",
  1875.         tfontptr->dvi_fnum,
  1876.         tfontptr->dvi_check,
  1877.         tfontptr->dvi_s,
  1878.         tfontptr->dvi_d,
  1879.         tfontptr->dvi_alen,
  1880.         tfontptr->dvi_nlen,
  1881.         tfontptr->dvi_name,
  1882.         tfontptr->font_mag,
  1883.         D_mag
  1884.     );
  1885.     }
  1886. #endif DEBUG
  1887.  
  1888.     /* go find the font file */
  1889.     if (!FindFontFile(G_fontpath,G_fontpathsize,
  1890.         tfontptr->dvi_name,tfontptr->font_mag,tfontptr->name,
  1891.         nname, &nmag)) {
  1892.     Fatal("no font %s.%d\n",tfontptr->dvi_name,tfontptr->font_mag);
  1893.     }
  1894.  
  1895.     /* set postscript font name - dvi name plus mag (i.e. file name) */
  1896.     sprintf(tfontptr->psname, "%s.%d", tfontptr->dvi_name, tfontptr->font_mag);
  1897.     if (tfontptr != G_pfontptr) OpenFontFile();
  1898.  
  1899. #ifdef USEPXL
  1900.     /* allow missing pxl files */
  1901.     if ( G_fontfp == NO_FILE ) {
  1902.     tfontptr->magnification = 0;
  1903.     tfontptr->designsize = 0;
  1904.     /* initialize the character data */
  1905.     for (i = 0; i <= MAXFONTCHARS-1; i++) {
  1906.         tcharptr = &(tfontptr->ch[i]);
  1907.         tcharptr->width = 0;
  1908.         tcharptr->height = 0;
  1909.         tcharptr->xOffset= 0;
  1910.         tcharptr->yOffset = 0;
  1911.         tcharptr->where.isloaded = FALSE;
  1912.         tcharptr->where.address.fileOffset = NONEXISTANT;
  1913.         tcharptr->tfmw = 0;
  1914.     }
  1915.     return;
  1916.     }
  1917.  
  1918.     /* check the version number */
  1919.     if ((t = GET4(G_fontfp)) != PXLID) {
  1920.     Fatal("PXL ID = %d, can only process PXL ID = %d files", t, PXLID);
  1921.     }
  1922.  
  1923.     /* check that the "checksum" matches */
  1924.     fseek(G_fontfp, -20, FROM_END);    /* magic number */
  1925.     t = GET4(G_fontfp);
  1926.     if ((tfontptr->dvi_check != 0) && (t != 0) && (tfontptr->dvi_check != t)) {
  1927.     Warning("font = \"%s\",\n-->font checksum = %d,\n-->dvi checksum = %d",
  1928.         tfontptr->name, tfontptr->dvi_check, t);
  1929.     }
  1930.  
  1931.     tfontptr->magnification = GET4(G_fontfp);
  1932.     tfontptr->designsize = GET4(G_fontfp);
  1933.  
  1934.     /* get the character info */
  1935.     fseek(G_fontfp, GET4(G_fontfp) * 4, FROM_START);
  1936.  
  1937.     for (i = 0; i <= MAXFONTCHARS-1; i++) {
  1938.     tcharptr = &(tfontptr->ch[i]);
  1939.     tcharptr->width = GET2(G_fontfp);
  1940.     tcharptr->height = GET2(G_fontfp);
  1941.     tcharptr->xOffset= GETSN(G_fontfp, 2);
  1942.     tcharptr->yOffset = GETSN(G_fontfp, 2);
  1943.     tcharptr->where.isloaded = FALSE;
  1944.     tcharptr->where.address.fileOffset = GET4(G_fontfp) * 4;
  1945.     tcharptr->tfmw = ((float)GET4(G_fontfp)*(float)tfontptr->dvi_s) /
  1946.         (float)(1<<20);
  1947.     }
  1948.  
  1949. #else not USEPXL
  1950.     /* allow missing gf files */
  1951.     if ( G_fontfp == NO_FILE ) {
  1952.     for (i = 0; i <= MAXFONTCHARS-1; i++) {
  1953.         tcharptr = &(tfontptr->ch[i]);
  1954.         tcharptr->where.isloaded = FALSE;
  1955.         tcharptr->where.address.fileOffset = NONEXISTANT;
  1956.         tcharptr->tfmw = 0;
  1957.     }
  1958.     return;
  1959.     }
  1960.  
  1961.     /* get the character info from gf font file */
  1962.     gf_infile = G_fontfp;
  1963.     gf_filename = tfontptr->name;        /* used in gf reader */
  1964.     gf_seekpost();
  1965.     gf_readpost();
  1966.  
  1967.     /* check the checksum */
  1968.     if ((tfontptr->dvi_check != 0)
  1969.         && (gf_checksum != 0)
  1970.         && (tfontptr->dvi_check != gf_checksum)) {
  1971.     Warning("font = \"%s\",\n-->font checksum = %d,\n-->dvi checksum = %d",
  1972.         tfontptr->name, tfontptr->dvi_check, gf_checksum);
  1973.     }
  1974.  
  1975.     /* initialize the character info */
  1976.     for(i=0; i<=MAXFONTCHARS-1; i++) {
  1977.     tcharptr = &(tfontptr->ch[i]);
  1978.     tcharptr->where.isloaded = FALSE;
  1979.     if (gf_char_exists[i]) {
  1980.         tcharptr->tfmw = ((float)gf_tfm_wd[i]*(float)tfontptr->dvi_s) /
  1981.         (float)(1<<20);
  1982.         tcharptr->where.address.fileOffset = gf_char_pointer[i];
  1983.     } else {
  1984.         tcharptr->where.address.fileOffset = NONEXISTANT;
  1985.         tcharptr->tfmw = 0;
  1986.     }
  1987.     }
  1988. #endif not USEPXL
  1989. }
  1990.  
  1991. /*-->FindPostAmble*/
  1992. /**********************************************************************/
  1993. /************************  FindPostAmble  **************************/
  1994. /**********************************************************************/
  1995. /* this routine will move to the end of the file and find the start
  1996.     of the postamble */
  1997.  
  1998. void
  1999. FindPostAmble()
  2000. {
  2001.     register long postambleptr;
  2002.     register int i;
  2003.  
  2004.     /* this seems like a dumb way to do this */
  2005.     /* why not just seek 4 from end */
  2006.     fseek (G_dvifp, (long) 0, FROM_END);   /* goto end of file */
  2007.     postambleptr = ftell (G_dvifp) - 4;
  2008.     fseek (G_dvifp, postambleptr, FROM_START);
  2009.  
  2010.     while (TRUE) {
  2011.     fseek (G_dvifp, --(postambleptr), FROM_START);
  2012.     if (((i = GET1(G_dvifp)) != 223) && (i != DVIFORMAT)) {
  2013.         Fatal ("Bad end of DVI file");
  2014.     }
  2015.     if (i == DVIFORMAT) break;
  2016.     }
  2017.     fseek (G_dvifp, (postambleptr) - 4, FROM_START);
  2018.     postambleptr = GET4(G_dvifp);
  2019.     G_postambleptr = postambleptr;
  2020.     fseek (G_dvifp, postambleptr, FROM_START);
  2021. }
  2022.  
  2023. /*-->CheckPreAmble*/
  2024. /**********************************************************************/
  2025. /**************************  CheckPreAmble  ***************************/
  2026. /**********************************************************************/
  2027.  
  2028. void
  2029. CheckPreAmble()
  2030. {
  2031.     register int i;
  2032.  
  2033.     /* check for presence of pre-amble */
  2034.     if ((i = GET1(G_dvifp)) != PRE)  {
  2035.     Fatal("PRE doesn't occur first--are you sure this is a DVI file?\n\n");
  2036.     }
  2037.  
  2038.     /* check for correct DVI file format */
  2039.     i = GET1(G_dvifp);
  2040.     if (i != DVIFORMAT)  {
  2041.     Fatal("DVI format = %d, can only process DVI format %d files\n\n",
  2042.         i, DVIFORMAT);
  2043.     }
  2044. }
  2045.  
  2046. /*-->ReadPreAmble*/
  2047. /**********************************************************************/
  2048. /**************************  ReadPreAmble  ***************************/
  2049. /**********************************************************************/
  2050.  
  2051. void
  2052. ReadPreAmble()
  2053. {
  2054.     char sname[STRSIZE];
  2055.     register int k;
  2056.  
  2057.     /* read the preamble */
  2058.     D_num = GET4(G_dvifp);
  2059.     D_den = GET4(G_dvifp);
  2060.     D_mag = GET4(G_dvifp);
  2061.  
  2062. #ifdef USEGLOBALMAG
  2063.     if (CL_usermag > 0 && CL_usermag != D_mag) {
  2064.     Warning("DVI magnification of %d over-ridden by user mag of %d\n",
  2065.             D_mag, CL_usermag );
  2066.     }
  2067. #endif USEGLOBALMAG
  2068.  
  2069.     if (CL_usermag > 0) D_mag = CL_usermag;
  2070.  
  2071. #ifndef USEGLOBALMAG
  2072.     if( D_mag != 1000 ) Warning("Magnification of %d ignored.\n", D_mag);
  2073. #endif USEGLOBALMAG
  2074.  
  2075.     G_hconv = DoConv(D_num, D_den, hconvRESOLUTION);
  2076.     G_vconv = DoConv(D_num, D_den, vconvRESOLUTION);
  2077.     k = GET1(G_dvifp);
  2078.     GetBytes(G_dvifp, sname, k);
  2079.     sname[k] = '\0';
  2080. #ifdef DEBUG
  2081.     if (Debug) Warning("internal - pre-string - %s\n",sname);
  2082. #endif DEBUG
  2083.  
  2084.     /* read the post-amble */
  2085.     ReadPostAmble(CL_PreLoad);
  2086.     if (CL_Reverse) {
  2087.     /* start on last page */
  2088.     fseek(G_dvifp, G_ppagep, FROM_START);
  2089.     } else {
  2090.     /* start on first page */
  2091.     fseek(G_dvifp, (long) 14, FROM_START);
  2092.     k = GET1(G_dvifp);
  2093.     GetBytes(G_dvifp, sname, k);
  2094.     }
  2095. }
  2096.  
  2097. /*-->ReadPostAmble*/
  2098. /**********************************************************************/
  2099. /**************************  ReadPostAmble  ***************************/
  2100. /**********************************************************************/
  2101. /***********************************************************************
  2102.     This  routine  is  used  to  read  in  the  postamble  values.    It
  2103.     initializes the magnification and checks  the stack height prior  to
  2104.     starting printing the document.
  2105. ***********************************************************************/
  2106.  
  2107. void
  2108. ReadPostAmble(load)
  2109. int     load;
  2110. {
  2111.     /* go find the post-amble */
  2112.     FindPostAmble();
  2113.     if (GET1(G_dvifp) != POST) Fatal ("POST missing at head of postamble");
  2114. #ifdef DEBUG
  2115.     if (Debug) fprintf (stderr, "got POST command\n");
  2116. #endif DEBUG
  2117.     G_ppagep = GET4(G_dvifp);
  2118.     D_num = GET4(G_dvifp);
  2119.     D_den = GET4(G_dvifp);
  2120.     D_mag = GET4(G_dvifp);
  2121. #ifdef USEGLOBALMAG
  2122.     if( CL_usermag > 0 && CL_usermag != D_mag )
  2123.     Warning("DVI magnification of %d over-ridden by user mag of %d\n", D_mag, CL_usermag );
  2124. #endif USEGLOBALMAG
  2125.     if( CL_usermag > 0 ) D_mag = CL_usermag;
  2126. #ifndef USEGLOBALMAG
  2127.     if( D_mag != 1000 ) Warning("Magnification of %d ignored.\n", D_mag);
  2128. #endif USEGLOBALMAG
  2129.     G_hconv = DoConv(D_num, D_den, hconvRESOLUTION);
  2130.     G_vconv = DoConv(D_num, D_den, vconvRESOLUTION);
  2131.  
  2132.     GET4(G_dvifp);    /* height-plus-depth of tallest page */
  2133.     GET4(G_dvifp);    /* width of widest page */
  2134.     if (GET2(G_dvifp) >= STACKSIZE)
  2135.     Fatal ("Stack size is too small - static allocation");
  2136.     GET2(G_dvifp);    /* this reads the number of pages in */
  2137.     /* the DVI file */
  2138. #ifdef DEBUG
  2139.     if (Debug) fprintf (stderr, "now reading font defs");
  2140. #endif DEBUG
  2141.     if (load) GetFontDef ();
  2142. }
  2143.  
  2144. /*-->LoadAChar*/
  2145. /**********************************************************************/
  2146. /*****************************  LoadAChar  ******************************/
  2147. /**********************************************************************/
  2148. /* control the output of a character bit map */
  2149. /* 1. read the bitmap from the font file */
  2150. /* 2. emit the bitmap to the output */
  2151.  
  2152. LoadAChar(ch, ceptr)
  2153.     int ch;
  2154.     register struct char_entry *ceptr;
  2155. {
  2156.     /* sanity checks */
  2157.     if (ceptr == NULL) {
  2158.     Fatal("internal - null pointer in LoadAChar\n");
  2159.     }
  2160.     if (ceptr->where.isloaded) {
  2161.     /* should not have been called */
  2162.     return;
  2163.     }
  2164.  
  2165.     /* always set these values - here are the defaults */
  2166.     ceptr->where.isloaded = TRUE;
  2167.  
  2168.     /* if there is no font file, no need to proceed */
  2169.     if (ceptr->where.address.fileOffset == NONEXISTANT) {
  2170.     ceptr->where.address.pixptr = NULL;
  2171.     return;
  2172.     }
  2173.  
  2174.     /* first open the font file */
  2175.     /* note current font is global variable G_fontptr */
  2176.     OpenFontFile();
  2177.  
  2178.     /* next read the bit map for this character from the font file */
  2179. #ifdef USEPXL
  2180.     fseek(G_fontfp, ceptr->where.address.fileOffset, FROM_START);
  2181.     nints = ((ceptr->width + 31) >> 5) * ceptr->height;
  2182.     if( (pr = (long *)malloc( nints*sizeof(long) )) == NULL ) {
  2183.     Fatal("Unable to allocate memory for char bit map\n");
  2184.     }
  2185.     fread(pr, 4, nints, G_fontfp);
  2186.     ceptr->where.address.pixptr = pr;
  2187.  
  2188. #else not USEPXL
  2189.  
  2190. #ifdef NOTDEF
  2191.     /* unless re-read postamble of font file, may have lost file offsets */
  2192.     gf_seekchar(ch);
  2193. #endif NOTDEF
  2194.     fseek(gf_infile, ceptr->where.address.fileOffset, FROM_START);
  2195.     gf_gettochar();
  2196.     gf_readbits();
  2197.     ceptr->where.address.pixptr = NULL;
  2198.  
  2199. #endif USEPXL
  2200.  
  2201.     /* now emit the bit map to the output */
  2202.     EmitCharBitMap(ch, ceptr);
  2203. #ifdef USEPXL
  2204.     /* we should really free the space used by the PXL data after this
  2205.        point, but it is not large, and besides, we may want to be
  2206.        more clever in the future, about sending bitmaps.  So keep
  2207.        the data around */
  2208. #endif USEPXL
  2209. }
  2210.  
  2211. /*-->SetChar*/
  2212. /**********************************************************************/
  2213. /*****************************  SetChar  ******************************/
  2214. /**********************************************************************/
  2215.  
  2216. void
  2217. SetChar(ch, command, PassNo)
  2218.     int ch, command, PassNo;
  2219. {
  2220.     register struct char_entry *ceptr;  /* temporary char_entry pointer */
  2221.  
  2222.     /* who sets G_fontptr? (OpenFontFile,SetFontNum) */
  2223.     if (G_fontptr == NULL) {
  2224.     Fatal("internal - unexpected null font in SetChar()\n");
  2225.     }
  2226.     ceptr = &(G_fontptr->ch[ch]);
  2227.     if (!ceptr->where.isloaded) LoadAChar(ch, ceptr);
  2228.     if (PassNo==0) return;
  2229.  
  2230.     SetPosn(G_h,G_v);
  2231.     if (G_fontptr->font_file_id != NO_FILE) {      /* ignore missing fonts */
  2232.     EMITN(ch); EMITS("c\n");
  2233.     G_hh += ceptr->tfmw;
  2234.     }
  2235.  
  2236.     /* if this is a set, then move, if this is a put, then do not move */
  2237.     if (command <= SET4) MoveOver(ceptr->tfmw);
  2238.  
  2239. #ifdef STATS
  2240.     S_tnc += 1;
  2241.     G_fontptr->ncts += 1;
  2242. #endif STATS
  2243. }
  2244.  
  2245. /*-->SetFontNum*/
  2246. /**********************************************************************/
  2247. /****************************  SetFontNum  *****************************/
  2248. /**********************************************************************/
  2249. /*  this routine is used to specify the font to be used in printing future
  2250.     characters */
  2251.  
  2252. void
  2253. SetFontNum(fontnum, Emitting)
  2254.     int fontnum, Emitting;
  2255. {
  2256.     register struct font_entry *fontp;
  2257.  
  2258.     /* linear search of font entry list */
  2259.     fontp = G_hfontptr;
  2260.     while ((fontp != NULL) && (fontp->dvi_fnum != fontnum)) {
  2261.     fontp = fontp->next;
  2262.     }
  2263.     if (fontp == NULL) {
  2264.     Fatal("font %d undefined", fontnum);
  2265.     }
  2266.     if (Emitting && (fontp->font_file_id != NO_FILE) )  {
  2267.     EMIT(G_outfp,"%s @sf\n", fontp->psname);
  2268.     }
  2269.     G_fontptr = fontp;
  2270. }
  2271.  
  2272. /*-->SetPosn*/
  2273. /**********************************************************************/
  2274. /*****************************  SetPosn  ******************************/
  2275. /**********************************************************************/
  2276. /* output a positioning command */
  2277.  
  2278. void
  2279. SetPosn(x, y)
  2280.     int x, y;
  2281. {
  2282.     register int rx;
  2283. #ifdef NOTDEF
  2284.     register int ry;
  2285. #endif NOTDEF
  2286.  
  2287. #ifdef USERELPOS
  2288.     /* use relative movement if just moving horizontally */
  2289.     if (y == G_vv) {
  2290.         if ( x != G_hh ) {
  2291.         EMITN(rx=PixRound(x-G_hh,G_hconv));
  2292.         EMITS("r ");
  2293.         G_hh += rx*G_hconv;
  2294.         }
  2295.     } else {
  2296. #endif USERELPOS
  2297.         EMITN(rx=PixRound(x,G_hconv));
  2298.         EMITN(PixRound(y,G_vconv));
  2299. #ifdef NOTDEF
  2300.         EMITN(ry=PixRound(y,G_vconv));
  2301. #endif NOTDEF
  2302.         EMITS("p ");
  2303.  
  2304.         /* must know where device "really" is horizontally, */
  2305.         /* for rel. posning. */
  2306.         /* but we always use direct positioning for vertical movement */
  2307.         G_hh = rx*G_hconv;
  2308.         G_vv = y;
  2309. #ifdef USERELPOS
  2310.     }
  2311. #endif USERELPOS
  2312. }
  2313.  
  2314. /*-->SetRule*/
  2315. /**********************************************************************/
  2316. /*****************************  SetRule  ******************************/
  2317. /**********************************************************************/
  2318. /* this routine will draw a rule (a line) */
  2319.  
  2320. void
  2321. SetRule(a, b, Set)
  2322.     int a, b;
  2323.     BOOLEAN Set;
  2324. {
  2325.     if( a > 0 && b > 0 ) {
  2326.     SetPosn(G_h,G_v);        /* lower left corner */
  2327.     EMITN(PixRound(b,G_hconv));    /* width */
  2328.     EMITN(PixRound(a,G_vconv));    /* height */
  2329.     EMITS("ru\n");
  2330.     } else {
  2331.     Warning("internal - bad value to SetRule (%d,%d)\n",a,b);
  2332.     }
  2333.     /* perform a move also? true for set, false for put */
  2334.     if (Set) MoveOver(b);
  2335. }
  2336.  
  2337. /*-->SetString*/
  2338. /**********************************************************************/
  2339. /*****************************  SetString  ****************************/
  2340. /**********************************************************************/
  2341. /* read and set a consecutive string of chars */
  2342.  
  2343. void
  2344. SetString(firstch, PassNo)
  2345.     register int firstch;
  2346.     int PassNo;
  2347. {
  2348.     register int ch;
  2349.     register struct char_entry *ceptr;
  2350.     register struct font_entry *fontp;
  2351.     register int len;
  2352.  
  2353.     /* sanity check */
  2354.     fontp = G_fontptr;
  2355.     if (fontp == NULL) {
  2356.     Fatal("internal - null font pointer - SetString()\n");
  2357.     }
  2358.  
  2359.     /* on the first pass, just read string and load fonts */
  2360.     if (PassNo == 0) {
  2361.     /* read entire string of chars */
  2362.     for (ch = firstch; ch >= SETC_000 && ch <= SETC_127; ch = GET1(G_dvifp)) {
  2363.         ceptr = &(fontp->ch[ch]);
  2364.         if (!(ceptr->where.isloaded)) LoadAChar(ch, ceptr);
  2365.     }
  2366.     UNGET1(G_dvifp, ch);    /* backup one character */
  2367.     return;
  2368.     }
  2369.  
  2370.     /* this is the second pass - emit */
  2371.     len = 1;
  2372.     SetPosn(G_h,G_v);
  2373.  
  2374.     /* alway emit the first character, so compute movement */
  2375.     ceptr = &(fontp->ch[firstch]);
  2376.     G_h += ceptr->tfmw;
  2377.     /* ignore missing fonts */
  2378.     if (fontp->font_file_id != NO_FILE) {
  2379.     /* this will force a movement by SetPosn() later */
  2380.     G_hh += ceptr->tfmw;
  2381.     }
  2382.  
  2383.     /* read entire string of chars */
  2384.     /* first check for more compact case of one char */
  2385.     ch = GET1(G_dvifp);
  2386.     if (ch < SETC_000 || ch > SETC_127) {
  2387.     /* only one character to emit */
  2388.     EMITN(firstch); 
  2389.     EMITS("c\n"); 
  2390.     } else {
  2391.     /* start a sting */
  2392.     EMITC('(');
  2393.     /* emit the first char */
  2394.     if ((firstch < ' ') || (firstch >= 0177)) {
  2395.         /* non-printable character */
  2396.         EMITO(firstch);
  2397.     } else if (firstch == '(' || firstch == ')' || firstch == '\\') {
  2398.         /* escaped character */
  2399.         EMITC('\\'); 
  2400.         EMITC(firstch); 
  2401.     } else {
  2402.         EMITC(firstch);
  2403.     }
  2404.     while (ch >= SETC_000 && ch <= SETC_127) {
  2405.         len += 1;
  2406.         /* move the current location accordingly */
  2407.         ceptr = &(fontp->ch[ch]);
  2408.         G_h += ceptr->tfmw;
  2409.         /* ignore missing fonts */
  2410.         if (fontp->font_file_id != NO_FILE) {
  2411.         if (ch < ' ' || ch >= 0177) {
  2412.             EMITO(ch);
  2413.         } else if (ch == '(' || ch == ')' || ch == '\\') {
  2414.             EMITC('\\'); 
  2415.             EMITC(ch); 
  2416.         } else {
  2417.             EMITC(ch);
  2418.         }
  2419.         /* this will force a movement by SetPosn() later */
  2420.         G_hh += ceptr->tfmw;
  2421.         }
  2422.         ch = GET1(G_dvifp);
  2423.     }
  2424.     EMITS(") s\n");
  2425.     }
  2426.     UNGET1(G_dvifp, ch);    /* backup one character */
  2427.  
  2428. #ifdef STATS
  2429.     S_tnc += len;
  2430.     fontp->ncts += len;
  2431. #endif STATS
  2432. }
  2433.  
  2434. /*-->SignExtend*/
  2435. /**********************************************************************/
  2436. /****************************  SignExtend  ****************************/
  2437. /**********************************************************************/
  2438.  
  2439. int
  2440. SignExtend(fp, n)   /* return n byte quantity from file fd */
  2441. register FILE *fp;  /* file pointer    */
  2442. register int n;     /* number of bytes */
  2443. {
  2444.     int n1;     /* number of bytes        */
  2445.     register int x; /* number being constructed */
  2446.  
  2447.     x = getc(fp);   /* get first (high-order) byte */
  2448.     n1 = n--;
  2449.     while (n--)  {
  2450.     x <<= 8;
  2451.     x |= getc(fp);
  2452.     }
  2453.  
  2454.     /* NOTE: This code assumes that the right-shift is an arithmetic, rather
  2455.     than logical, shift which will propagate the sign bit right.   According
  2456.     to Kernighan and Ritchie, this is compiler dependent! */
  2457.  
  2458.     x<<=32-8*n1;
  2459.     x>>=32-8*n1;  /* sign extend */
  2460.  
  2461. #ifdef DEBUG
  2462.     if (Debug) {
  2463.     fprintf(stderr,"\tSignExtend(fp,%d)=%X\n",n1,x);
  2464.     }
  2465. #endif DEBUG
  2466.     return(x);
  2467. }
  2468.  
  2469. /*-->SkipFontDef*/
  2470. /**********************************************************************/
  2471. /****************************  SkipFontDef  ***************************/
  2472. /**********************************************************************/
  2473.  
  2474. void
  2475. SkipFontDef()
  2476. {
  2477.     register int a, l;
  2478.  
  2479.     SKIP(G_dvifp,12);
  2480.     a = GET1(G_dvifp);
  2481.     l = GET1(G_dvifp);
  2482.     SKIP(G_dvifp,a+l);
  2483. }
  2484.  
  2485. /*-->Progress*/
  2486. /**********************************************************************/
  2487. /*****************************  Progress  ******************************/
  2488. /**********************************************************************/
  2489. /* all communication to the user about progress goes through here */
  2490. /* VARARGS1 for lint */
  2491.  
  2492. void
  2493. Progress(fmt, a, b, c, d, e, f)    /* issue a warning */
  2494. char *fmt;            /* format   */
  2495. char *a, *b, *c, *d, *e, *f;    /* arguments */
  2496. {
  2497.     /* only print if not quiet */
  2498.     if (G_quiet) return;
  2499.     fprintf(stderr, fmt, a, b, c, d, e, f);
  2500.  
  2501.     /* print in log file, if logging */
  2502.     if (G_logging) {
  2503.     if (G_logfp == NULL) {
  2504.         Fatal("missing log file\n");
  2505.     }
  2506.     fprintf(G_logfp, fmt, a, b, c, d, e, f);
  2507.     }
  2508. }
  2509.  
  2510. /*-->Warning*/
  2511. /**********************************************************************/
  2512. /*****************************  Warning  ******************************/
  2513. /**********************************************************************/
  2514. /* why is this routine so complicated? */
  2515. /* why is this routine used in some places and not in others? */
  2516. /* is G_logfp different than stderr? */
  2517. /* VARARGS1 for lint */
  2518.  
  2519. void
  2520. Warning(fmt, a, b, c, d, e, f)    /* issue a warning */
  2521. char *fmt;            /* format   */
  2522. char *a, *b, *c, *d, *e, *f;    /* arguments */
  2523. {
  2524.     G_errenc = TRUE;
  2525.     if (G_nowarn) return;
  2526.     fprintf(stderr, "%s: ", G_progname);
  2527.     fprintf(stderr, fmt, a, b, c, d, e, f);
  2528.  
  2529.     /* print in log file, if logging */
  2530.     if (G_logging) {
  2531.     if (G_logfp == NULL) {
  2532.         Fatal("missing log file\n");
  2533.     }
  2534.     fprintf(G_logfp, "%s: ", G_progname);
  2535.     fprintf(G_logfp, fmt, a, b, c, d, e, f);
  2536.     }
  2537. }
  2538.  
  2539. /**********************************************************************/
  2540.  
  2541.